2 // $ phantomjs tests.js
5 var page
= require('webpage').create();
6 var url
= 'src/index.html';
7 var testMaxTime
= 20000;
14 page
.onResourceError = function(e
) {
15 console
.log("Error loading " + e
.url
);
20 console
.log("Failed");
24 function waitForGenerate(fn
, maxTime
) {
26 maxTime
= testMaxTime
;
28 var start
= new Date().getTime();
29 var prevAddressCount
= -1;
30 var wait
= function keepWaiting() {
31 var now
= new Date().getTime();
32 var hasTimedOut
= now
- start
> maxTime
;
33 var addressCount
= page
.evaluate(function() {
34 return $(".address").length
;
36 var hasFinished
= addressCount
> 0 && addressCount
== prevAddressCount
;
37 prevAddressCount
= addressCount
;
41 else if (hasTimedOut
) {
42 console
.log("Test timed out");
46 setTimeout(keepWaiting
, 100);
52 function waitForFeedback(fn
, maxTime
) {
54 maxTime
= testMaxTime
;
56 var start
= new Date().getTime();
57 var wait
= function keepWaiting() {
58 var now
= new Date().getTime();
59 var hasTimedOut
= now
- start
> maxTime
;
61 console
.log("Test timed out");
65 var feedback
= page
.evaluate(function() {
66 var feedback
= $(".feedback");
67 if (feedback
.css("display") == "none") {
70 return feedback
.text();
72 var hasFinished
= feedback
.length
> 0 && feedback
!= "Calculating...";
77 setTimeout(keepWaiting
, 100);
83 function waitForEntropyFeedback(fn
, maxTime
) {
85 maxTime
= testMaxTime
;
87 var origFeedback
= page
.evaluate(function() {
88 return $(".entropy-container").text();
90 var start
= new Date().getTime();
91 var wait
= function keepWaiting() {
92 var now
= new Date().getTime();
93 var hasTimedOut
= now
- start
> maxTime
;
95 console
.log("Test timed out");
99 var feedback
= page
.evaluate(function() {
100 return $(".entropy-container").text();
102 var hasFinished
= feedback
!= origFeedback
;
107 setTimeout(keepWaiting
, 100);
114 if (tests
.length
> 0) {
115 var testsStr
= tests
.length
== 1 ? "test" : "tests";
116 console
.log(tests
.length
+ " " + testsStr
+ " remaining");
120 console
.log("Finished with 0 failures");
126 * Randomize array element order in-place.
127 * Using Durstenfeld shuffle algorithm.
128 * See http://stackoverflow.com/a/12646864
130 function shuffle(array
) {
131 for (var i
= array
.length
- 1; i
> 0; i
--) {
132 var j
= Math
.floor(Math
.random() * (i
+ 1));
142 // Page loads with status of 'success'
144 page
.open(url
, function(status
) {
145 if (status
!= "success") {
146 console
.log("Page did not load with status 'success'");
155 page
.open(url
, function(status
) {
156 var content
= page
.evaluate(function() {
157 return document
.body
.textContent
.trim();
160 console
.log("Page does not have text");
167 // Entering mnemonic generates addresses
169 page
.open(url
, function(status
) {
171 page
.evaluate(function() {
172 $(".phrase").val("abandon abandon ability").trigger("input");
175 waitForGenerate(function() {
176 var addressCount
= page
.evaluate(function() {
177 return $(".address").length
;
179 if (addressCount
!= 20) {
180 console
.log("Mnemonic did not generate addresses");
181 console
.log("Expected: " + expected
);
182 console
.log("Got: " + actual
);
190 // Random button generates random mnemonic
192 page
.open(url
, function(status
) {
193 // check initial phrase is empty
194 var phrase
= page
.evaluate(function() {
195 return $(".phrase").text();
198 console
.log("Initial phrase is not blank");
201 // press the 'generate' button
202 page
.evaluate(function() {
203 $(".generate").click();
205 // get the new phrase
206 waitForGenerate(function() {
207 var phrase
= page
.evaluate(function() {
208 return $(".phrase").val();
210 if (phrase
.length
<= 0) {
211 console
.log("Phrase not generated by pressing button");
219 // Mnemonic length can be customized
221 page
.open(url
, function(status
) {
222 // set the length to 6
223 var expectedLength
= "6";
224 page
.evaluate(function() {
225 $(".strength option[selected]").removeAttr("selected");
226 $(".strength option[value=6]").prop("selected", true);
228 // press the 'generate' button
229 page
.evaluate(function() {
230 $(".generate").click();
232 // check the new phrase is six words long
233 waitForGenerate(function() {
234 var actualLength
= page
.evaluate(function() {
235 var words
= $(".phrase").val().split(" ");
238 if (actualLength
!= expectedLength
) {
239 console
.log("Phrase not generated with correct length");
240 console
.log("Expected: " + expectedLength
);
241 console
.log("Actual: " + actualLength
);
249 // Passphrase can be set
251 page
.open(url
, function(status
) {
252 // set the phrase and passphrase
253 var expected
= "15pJzUWPGzR7avffV9nY5by4PSgSKG9rba";
254 page
.evaluate(function() {
255 $(".phrase").val("abandon abandon ability");
256 $(".passphrase").val("secure_passphrase").trigger("input");
258 // check the address is generated correctly
259 waitForGenerate(function() {
260 var actual
= page
.evaluate(function() {
261 return $(".address:first").text();
263 if (actual
!= expected
) {
264 console
.log("Passphrase results in wrong address");
265 console
.log("Expected: " + expected
);
266 console
.log("Actual: " + actual
);
274 // Network can be set to bitcoin testnet
276 page
.open(url
, function(status
) {
277 // set the phrase and coin
278 var expected
= "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi";
279 page
.evaluate(function() {
280 $(".phrase").val("abandon abandon ability");
281 $(".phrase").trigger("input");
282 $(".network option[selected]").removeAttr("selected");
283 $(".network option").filter(function() {
284 return $(this).html() == "BTC - Bitcoin Testnet";
285 }).prop("selected", true);
286 $(".network").trigger("change");
288 // check the address is generated correctly
289 waitForGenerate(function() {
290 var actual
= page
.evaluate(function() {
291 return $(".address:first").text();
293 if (actual
!= expected
) {
294 console
.log("Bitcoin testnet address is incorrect");
295 console
.log("Expected: " + expected
);
296 console
.log("Actual: " + actual
);
304 // Network can be set to litecoin
306 page
.open(url
, function(status
) {
307 // set the phrase and coin
308 var expected
= "LQ4XU8RX2ULPmPq9FcUHdVmPVchP9nwXdn";
309 page
.evaluate(function() {
310 $(".phrase").val("abandon abandon ability");
311 $(".phrase").trigger("input");
312 $(".network option[selected]").removeAttr("selected");
313 $(".network option").filter(function() {
314 return $(this).html() == "LTC - Litecoin";
315 }).prop("selected", true);
316 $(".network").trigger("change");
318 // check the address is generated correctly
319 waitForGenerate(function() {
320 var actual
= page
.evaluate(function() {
321 return $(".address:first").text();
323 if (actual
!= expected
) {
324 console
.log("Litecoin address is incorrect");
325 console
.log("Expected: " + expected
);
326 console
.log("Actual: " + actual
);
334 // Network can be set to ripple
336 page
.open(url
, function(status
) {
337 // set the phrase and coin
338 var expected
= "rLTFnqbmCVPGx6VfaygdtuKWJgcN4v1zRS";
339 page
.evaluate(function() {
340 $(".phrase").val("ill clump only blind unit burden thing track silver cloth review awake useful craft whale all satisfy else trophy sunset walk vanish hope valve");
341 $(".phrase").trigger("input");
342 $(".network option[selected]").removeAttr("selected");
343 $(".network option").filter(function() {
344 return $(this).html() == "XRP - Ripple";
345 }).prop("selected", true);
346 $(".network").trigger("change");
348 // check the address is generated correctly
349 waitForGenerate(function() {
350 var actual
= page
.evaluate(function() {
351 return $(".address:first").text();
353 if (actual
!= expected
) {
354 console
.log("Ripple address is incorrect");
355 console
.log("Expected: " + expected
);
356 console
.log("Actual: " + actual
);
364 // Network can be set to dogecoin
366 page
.open(url
, function(status
) {
367 // set the phrase and coin
368 var expected
= "DPQH2AtuzkVSG6ovjKk4jbUmZ6iXLpgbJA";
369 page
.evaluate(function() {
370 $(".phrase").val("abandon abandon ability");
371 $(".phrase").trigger("input");
372 $(".network option[selected]").removeAttr("selected");
373 $(".network option").filter(function() {
374 return $(this).html() == "DOGE - Dogecoin";
375 }).prop("selected", true);
376 $(".network").trigger("change");
378 // check the address is generated correctly
379 waitForGenerate(function() {
380 var actual
= page
.evaluate(function() {
381 return $(".address:first").text();
383 if (actual
!= expected
) {
384 console
.log("Dogecoin address is incorrect");
385 console
.log("Expected: " + expected
);
386 console
.log("Actual: " + actual
);
394 // Network can be set to shadowcash
396 page
.open(url
, function(status
) {
397 // set the phrase and coin
398 var expected
= "SiSZtfYAXEFvMm3XM8hmtkGDyViRwErtCG";
399 page
.evaluate(function() {
400 $(".phrase").val("abandon abandon ability");
401 $(".phrase").trigger("input");
402 $(".network option[selected]").removeAttr("selected");
403 $(".network option").filter(function() {
404 return $(this).html() == "SDC - ShadowCash";
405 }).prop("selected", true);
406 $(".network").trigger("change");
408 // check the address is generated correctly
409 waitForGenerate(function() {
410 var actual
= page
.evaluate(function() {
411 return $(".address:first").text();
413 if (actual
!= expected
) {
414 console
.log("Shadowcash address is incorrect");
415 console
.log("Expected: " + expected
);
416 console
.log("Actual: " + actual
);
424 // Network can be set to shadowcash testnet
426 page
.open(url
, function(status
) {
427 // set the phrase and coin
428 var expected
= "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
429 page
.evaluate(function() {
430 $(".phrase").val("abandon abandon ability");
431 $(".phrase").trigger("input");
432 $(".network option[selected]").removeAttr("selected");
433 $(".network option").filter(function() {
434 return $(this).html() == "SDC - ShadowCash Testnet";
435 }).prop("selected", true);
436 $(".network").trigger("change");
438 // check the address is generated correctly
439 waitForGenerate(function() {
440 var actual
= page
.evaluate(function() {
441 return $(".address:first").text();
443 if (actual
!= expected
) {
444 console
.log("Shadowcash testnet address is incorrect");
445 console
.log("Expected: " + expected
);
446 console
.log("Actual: " + actual
);
454 // Network can be set to viacoin
456 page
.open(url
, function(status
) {
457 // set the phrase and coin
458 var expected
= "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
459 page
.evaluate(function() {
460 $(".phrase").val("abandon abandon ability");
461 $(".phrase").trigger("input");
462 $(".network option[selected]").removeAttr("selected");
463 $(".network option").filter(function() {
464 return $(this).html() == "VIA - Viacoin";
465 }).prop("selected", true);
466 $(".network").trigger("change");
468 // check the address is generated correctly
469 waitForGenerate(function() {
470 var actual
= page
.evaluate(function() {
471 return $(".address:first").text();
473 if (actual
!= expected
) {
474 console
.log("Viacoin address is incorrect");
475 console
.log("Expected: " + expected
);
476 console
.log("Actual: " + actual
);
484 // Network can be set to viacoin testnet
486 page
.open(url
, function(status
) {
487 // set the phrase and coin
488 var expected
= "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
489 page
.evaluate(function() {
490 $(".phrase").val("abandon abandon ability");
491 $(".phrase").trigger("input");
492 $(".network option[selected]").removeAttr("selected");
493 $(".network option").filter(function() {
494 return $(this).html() == "VIA - Viacoin Testnet";
495 }).prop("selected", true);
496 $(".network").trigger("change");
498 // check the address is generated correctly
499 waitForGenerate(function() {
500 var actual
= page
.evaluate(function() {
501 return $(".address:first").text();
503 if (actual
!= expected
) {
504 console
.log("Viacoin testnet address is incorrect");
505 console
.log("Expected: " + expected
);
506 console
.log("Actual: " + actual
);
514 // Network can be set to jumbucks
516 page
.open(url
, function(status
) {
517 // set the phrase and coin
518 var expected
= "JLEXccwDXADK4RxBPkRez7mqsHVoJBEUew";
519 page
.evaluate(function() {
520 $(".phrase").val("abandon abandon ability");
521 $(".phrase").trigger("input");
522 $(".network option[selected]").removeAttr("selected");
523 $(".network option").filter(function() {
524 return $(this).html() == "JBS - Jumbucks";
525 }).prop("selected", true);
526 $(".network").trigger("change");
528 // check the address is generated correctly
529 waitForGenerate(function() {
530 var actual
= page
.evaluate(function() {
531 return $(".address:first").text();
533 if (actual
!= expected
) {
534 console
.log("Jumbucks address is incorrect");
535 console
.log("Expected: " + expected
);
536 console
.log("Actual: " + actual
);
544 // Network can be set to clam
546 page
.open(url
, function(status
) {
547 // set the phrase and coin
548 var expected
= "xCp4sakjVx4pUAZ6cBCtuin8Ddb6U1sk9y";
549 page
.evaluate(function() {
550 $(".phrase").val("abandon abandon ability");
551 $(".phrase").trigger("input");
552 $(".network option[selected]").removeAttr("selected");
553 $(".network option").filter(function() {
554 return $(this).html() == "CLAM - Clams";
555 }).prop("selected", true);
556 $(".network").trigger("change");
558 // check the address is generated correctly
559 waitForGenerate(function() {
560 var actual
= page
.evaluate(function() {
561 return $(".address:first").text();
563 if (actual
!= expected
) {
564 console
.log("CLAM address is incorrect");
565 console
.log("Expected: " + expected
);
566 console
.log("Actual: " + actual
);
574 // Network can be set to crown
576 page
.open(url
, function(status
) {
577 // set the phrase and coin
578 var expected
= "18pWSwSUAQdiwMHUfFZB1fM2xue9X1FqE5";
579 page
.evaluate(function() {
580 $(".phrase").val("abandon abandon ability");
581 $(".phrase").trigger("input");
582 $(".network option[selected]").removeAttr("selected");
583 $(".network option").filter(function() {
584 return $(this).html() == "CRW - Crown";
585 }).prop("selected", true);
586 $(".network").trigger("change");
588 // check the address is generated correctly
589 waitForGenerate(function() {
590 var actual
= page
.evaluate(function() {
591 return $(".address:first").text();
593 if (actual
!= expected
) {
594 console
.log("CRW address is incorrect");
595 console
.log("Expected: " + expected
);
596 console
.log("Actual: " + actual
);
604 // Network can be set to dash
606 page
.open(url
, function(status
) {
607 // set the phrase and coin
608 var expected
= "XdbhtMuGsPSkE6bPdNTHoFSszQKmK4S5LT";
609 page
.evaluate(function() {
610 $(".phrase").val("abandon abandon ability");
611 $(".phrase").trigger("input");
612 $(".network option[selected]").removeAttr("selected");
613 $(".network option").filter(function() {
614 return $(this).html() == "DASH - Dash";
615 }).prop("selected", true);
616 $(".network").trigger("change");
618 // check the address is generated correctly
619 waitForGenerate(function() {
620 var actual
= page
.evaluate(function() {
621 return $(".address:first").text();
623 if (actual
!= expected
) {
624 console
.log("DASH address is incorrect");
625 console
.log("Expected: " + expected
);
626 console
.log("Actual: " + actual
);
635 page
.open(url
, function(status
) {
636 // set the phrase and coin
637 var expected
= "yaR52EN4oojdJfBgzWJTymC4uuCLPT29Gw";
638 page
.evaluate(function() {
639 $(".phrase").val("abandon abandon ability");
640 $(".phrase").trigger("input");
641 $(".network option[selected]").removeAttr("selected");
642 $(".network option").filter(function() {
643 return $(this).html() == "DASH - Dash Testnet";
644 }).prop("selected", true);
645 $(".network").trigger("change");
647 // check the address is generated correctly
648 waitForGenerate(function() {
649 var actual
= page
.evaluate(function() {
650 return $(".address:first").text();
652 if (actual
!= expected
) {
653 console
.log("DASH Testnet address is incorrect");
654 console
.log("Expected: " + expected
);
655 console
.log("Actual: " + actual
);
663 // Network can be set to game
665 page
.open(url
, function(status
) {
666 // set the phrase and coin
667 var expected
= "GSMY9bAp36cMR4zyT4uGVS7GFjpdXbao5Q";
668 page
.evaluate(function() {
669 $(".phrase").val("abandon abandon ability");
670 $(".phrase").trigger("input");
671 $(".network option[selected]").removeAttr("selected");
672 $(".network option").filter(function() {
673 return $(this).html() == "GAME - GameCredits";
674 }).prop("selected", true);
675 $(".network").trigger("change");
677 // check the address is generated correctly
678 waitForGenerate(function() {
679 var actual
= page
.evaluate(function() {
680 return $(".address:first").text();
682 if (actual
!= expected
) {
683 console
.log("GAME address is incorrect");
684 console
.log("Expected: " + expected
);
685 console
.log("Actual: " + actual
);
693 // Network can be set to namecoin
695 page
.open(url
, function(status
) {
696 // set the phrase and coin
697 var expected
= "Mw2vK2Bvex1yYtYF6sfbEg2YGoUc98YUD2";
698 page
.evaluate(function() {
699 $(".phrase").val("abandon abandon ability");
700 $(".phrase").trigger("input");
701 $(".network option[selected]").removeAttr("selected");
702 $(".network option").filter(function() {
703 return $(this).html() == "NMC - Namecoin";
704 }).prop("selected", true);
705 $(".network").trigger("change");
707 // check the address is generated correctly
708 waitForGenerate(function() {
709 var actual
= page
.evaluate(function() {
710 return $(".address:first").text();
712 if (actual
!= expected
) {
713 console
.log("Namecoin address is incorrect");
714 console
.log("Expected: " + expected
);
715 console
.log("Actual: " + actual
);
723 // Network can be set to peercoin
725 page
.open(url
, function(status
) {
726 // set the phrase and coin
727 var expected
= "PVAiioTaK2eDHSEo3tppT9AVdBYqxRTBAm";
728 page
.evaluate(function() {
729 $(".phrase").val("abandon abandon ability");
730 $(".phrase").trigger("input");
731 $(".network option[selected]").removeAttr("selected");
732 $(".network option").filter(function() {
733 return $(this).html() == "PPC - Peercoin";
734 }).prop("selected", true);
735 $(".network").trigger("change");
737 // check the address is generated correctly
738 waitForGenerate(function() {
739 var actual
= page
.evaluate(function() {
740 return $(".address:first").text();
742 if (actual
!= expected
) {
743 console
.log("Peercoin address is incorrect");
744 console
.log("Expected: " + expected
);
745 console
.log("Actual: " + actual
);
753 // Network can be set to ethereum
756 page
.open(url
, function(status
) {
758 // set the phrase and coin
759 page
.evaluate(function() {
760 $(".phrase").val("abandon abandon ability");
761 $(".phrase").trigger("input");
762 $(".network option[selected]").removeAttr("selected");
763 $(".network option").filter(function() {
764 return $(this).html() == "ETH - Ethereum";
765 }).prop("selected", true);
766 $(".network").trigger("change");
768 waitForGenerate(function() {
769 // check the address is generated correctly
770 // this value comes from
771 // https://www.myetherwallet.com/#view-wallet-info
772 // Unusual capitalization is due to checksum
773 var expected
= "0xe5815d5902Ad612d49283DEdEc02100Bd44C2772";
774 var actual
= page
.evaluate(function() {
775 return $(".address:first").text();
777 if (actual
!= expected
) {
778 console
.log("Ethereum address is incorrect");
779 console
.log("Expected: " + expected
);
780 console
.log("Actual: " + actual
);
783 // check the private key is correct
784 // this private key can be imported into
785 // https://www.myetherwallet.com/#view-wallet-info
786 // and it should correlate to the address above
787 var expected
= "0x8f253078b73d7498302bb78c171b23ce7a8fb511987d2b2702b731638a4a15e7";
788 var actual
= page
.evaluate(function() {
789 return $(".privkey:first").text();
791 if (actual
!= expected
) {
792 console
.log("Ethereum privkey is incorrect");
793 console
.log("Expected: " + expected
);
794 console
.log("Actual: " + actual
);
797 // check the public key is correct
799 // don't have any third-party source to generate the expected value
800 //var expected = "?";
801 //var actual = page.evaluate(function() {
802 // return $(".pubkey:first").text();
804 //if (actual != expected) {
805 // console.log("Ethereum privkey is incorrect");
806 // console.log("Expected: " + expected);
807 // console.log("Actual: " + actual);
815 // Network can be set to Slimcoin
817 page
.open(url
, function(status
) {
818 // set the phrase and coin
819 var expected
= "SNzPi1CafHFm3WWjRo43aMgiaEEj3ogjww";
820 page
.evaluate(function() {
821 $(".phrase").val("abandon abandon ability");
822 $(".phrase").trigger("input");
823 $(".network option[selected]").removeAttr("selected");
824 $(".network option").filter(function() {
825 return $(this).html() == "SLM - Slimcoin";
826 }).prop("selected", true);
827 $(".network").trigger("change");
829 // check the address is generated correctly
830 waitForGenerate(function() {
831 var actual
= page
.evaluate(function() {
832 return $(".address:first").text();
834 if (actual
!= expected
) {
835 console
.log("Slimcoin address is incorrect");
836 console
.log("Expected: " + expected
);
837 console
.log("Actual: " + actual
);
845 // Network can be set to Slimcointn
847 page
.open(url
, function(status
) {
848 // set the phrase and coin
849 var expected
= "n3nMgWufTek5QQAr6uwMhg5xbzj8xqc4Dq";
850 page
.evaluate(function() {
851 $(".phrase").val("abandon abandon ability");
852 $(".phrase").trigger("input");
853 $(".network option[selected]").removeAttr("selected");
854 $(".network option").filter(function() {
855 return $(this).html() == "SLM - Slimcoin Testnet";
856 }).prop("selected", true);
857 $(".network").trigger("change");
859 // check the address is generated correctly
860 waitForGenerate(function() {
861 var actual
= page
.evaluate(function() {
862 return $(".address:first").text();
864 if (actual
!= expected
) {
865 console
.log("Slimcoin testnet address is incorrect");
866 console
.log("Expected: " + expected
);
867 console
.log("Actual: " + actual
);
875 // Network can be set to bitcoin cash
877 page
.open(url
, function(status
) {
878 // set the phrase and coin
879 var expected
= "1JKvb6wKtsjNoCRxpZ4DGrbniML7z5U16A";
880 page
.evaluate(function() {
881 $(".phrase").val("abandon abandon ability");
882 $(".phrase").trigger("input");
883 $(".network option[selected]").removeAttr("selected");
884 $(".network option").filter(function() {
885 return $(this).html() == "BCH - Bitcoin Cash";
886 }).prop("selected", true);
887 $(".network").trigger("change");
889 // check the address is generated correctly
890 waitForGenerate(function() {
891 var actual
= page
.evaluate(function() {
892 return $(".address:first").text();
894 if (actual
!= expected
) {
895 console
.log("Bitcoin Cash address is incorrect");
896 console
.log("Expected: " + expected
);
897 console
.log("Actual: " + actual
);
905 // Network can be set to myriadcoin
907 page
.open(url
, function(status
) {
908 // set the phrase and coin
909 var expected
= "MJEswvRR46wh9BoiVj9DzKYMBkCramhoBV";
910 page
.evaluate(function() {
911 $(".phrase").val("abandon abandon ability");
912 $(".phrase").trigger("input");
913 $(".network option[selected]").removeAttr("selected");
914 $(".network option").filter(function() {
915 return $(this).html() == "XMY - Myriadcoin";
916 }).prop("selected", true);
917 $(".network").trigger("change");
919 // check the address is generated correctly
920 waitForGenerate(function() {
921 var actual
= page
.evaluate(function() {
922 return $(".address:first").text();
924 if (actual
!= expected
) {
925 console
.log("Myriadcoin address is incorrect");
926 console
.log("Expected: " + expected
);
927 console
.log("Actual: " + actual
);
935 // Network can be set to pivx
937 page
.open(url
, function(status
) {
938 // set the phrase and coin
939 var expected
= "DBxgT7faCuno7jmtKuu6KWCiwqsVPqh1tS";
940 page
.evaluate(function() {
941 $(".phrase").val("abandon abandon ability");
942 $(".phrase").trigger("input");
943 $(".network option[selected]").removeAttr("selected");
944 $(".network option").filter(function() {
945 return $(this).html() == "PIVX - PIVX";
946 }).prop("selected", true);
947 $(".network").trigger("change");
949 // check the address is generated correctly
950 waitForGenerate(function() {
951 var actual
= page
.evaluate(function() {
952 return $(".address:first").text();
954 if (actual
!= expected
) {
955 console
.log("PIVX address is incorrect");
956 console
.log("Expected: " + expected
);
957 console
.log("Actual: " + actual
);
965 // Network can be set to pivx testnet
967 page
.open(url
, function(status
) {
968 // set the phrase and coin
969 var expected
= "yB5U384n6dGkVE3by5y9VdvHHPwPg68fQj";
970 page
.evaluate(function() {
971 $(".phrase").val("abandon abandon ability");
972 $(".phrase").trigger("input");
973 $(".network option[selected]").removeAttr("selected");
974 $(".network option").filter(function() {
975 return $(this).html() == "PIVX - PIVX Testnet";
976 }).prop("selected", true);
977 $(".network").trigger("change");
979 // check the address is generated correctly
980 waitForGenerate(function() {
981 var actual
= page
.evaluate(function() {
982 return $(".address:first").text();
984 if (actual
!= expected
) {
985 console
.log("PIVX Testnet address is incorrect");
986 console
.log("Expected: " + expected
);
987 console
.log("Actual: " + actual
);
995 // Network can be set to maza
997 page
.open(url
, function(status
) {
998 // set the phrase and coin
999 var expected
= "MGW4Bmi2NEm4PxSjgeFwhP9vg18JHoRnfw";
1000 page
.evaluate(function() {
1001 $(".phrase").val("abandon abandon ability");
1002 $(".phrase").trigger("input");
1003 $(".network option[selected]").removeAttr("selected");
1004 $(".network option").filter(function() {
1005 return $(this).html() == "MAZA - Maza";
1006 }).prop("selected", true);
1007 $(".network").trigger("change");
1009 // check the address is generated correctly
1010 waitForGenerate(function() {
1011 var actual
= page
.evaluate(function() {
1012 return $(".address:first").text();
1014 if (actual
!= expected
) {
1015 console
.log("Maza address is incorrect");
1016 console
.log("Expected: " + expected
);
1017 console
.log("Actual: " + actual
);
1025 // Network can be set to fujicoin
1027 page
.open(url
, function(status
) {
1028 // set the phrase and coin
1029 var expected
= "FgiaLpG7C99DyR4WnPxXedRVHXSfKzUDhF";
1030 page
.evaluate(function() {
1031 $(".phrase").val("abandon abandon ability");
1032 $(".phrase").trigger("input");
1033 $(".network option[selected]").removeAttr("selected");
1034 $(".network option").filter(function() {
1035 return $(this).html() == "FJC - Fujicoin";
1036 }).prop("selected", true);
1037 $(".network").trigger("change");
1039 // check the address is generated correctly
1040 waitForGenerate(function() {
1041 var actual
= page
.evaluate(function() {
1042 return $(".address:first").text();
1044 if (actual
!= expected
) {
1045 console
.log("Fujicoin address is incorrect");
1046 console
.log("Expected: " + expected
);
1047 console
.log("Actual: " + actual
);
1055 // Network can be set to nubits
1057 page
.open(url
, function(status
) {
1058 // set the phrase and coin
1059 var expected
= "BLxkabXuZSJSdesLD7KxZdqovd4YwyBTU6";
1060 page
.evaluate(function() {
1061 $(".phrase").val("abandon abandon ability");
1062 $(".phrase").trigger("input");
1063 $(".network option[selected]").removeAttr("selected");
1064 $(".network option").filter(function() {
1065 return $(this).html() == "USNBT - NuBits";
1066 }).prop("selected", true);
1067 $(".network").trigger("change");
1069 // check the address is generated correctly
1070 waitForGenerate(function() {
1071 var actual
= page
.evaluate(function() {
1072 return $(".address:first").text();
1074 if (actual
!= expected
) {
1075 console
.log("NuBits address is incorrect");
1076 console
.log("Expected: " + expected
);
1077 console
.log("Actual: " + actual
);
1085 // BIP39 seed is set from phrase
1087 page
.open(url
, function(status
) {
1089 var expected
= "20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3";
1090 page
.evaluate(function() {
1091 $(".phrase").val("abandon abandon ability");
1092 $(".phrase").trigger("input");
1094 // check the address is generated correctly
1095 waitForGenerate(function() {
1096 var actual
= page
.evaluate(function() {
1097 return $(".seed").val();
1099 if (actual
!= expected
) {
1100 console
.log("BIP39 seed is incorrectly generated from mnemonic");
1101 console
.log("Expected: " + expected
);
1102 console
.log("Actual: " + actual
);
1110 // BIP32 root key is set from phrase
1112 page
.open(url
, function(status
) {
1114 var expected
= "xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi";
1115 page
.evaluate(function() {
1116 $(".phrase").val("abandon abandon ability");
1117 $(".phrase").trigger("input");
1119 // check the address is generated correctly
1120 waitForGenerate(function() {
1121 var actual
= page
.evaluate(function() {
1122 return $(".root-key").val();
1124 if (actual
!= expected
) {
1125 console
.log("Root key is incorrectly generated from mnemonic");
1126 console
.log("Expected: " + expected
);
1127 console
.log("Actual: " + actual
);
1135 // Tabs show correct addresses when changed
1137 page
.open(url
, function(status
) {
1139 var expected
= "17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz";
1140 page
.evaluate(function() {
1141 $(".phrase").val("abandon abandon ability");
1142 $(".phrase").trigger("input");
1145 waitForGenerate(function() {
1146 page
.evaluate(function() {
1147 $("#bip32-tab a").click();
1149 // check the address is generated correctly
1150 waitForGenerate(function() {
1151 var actual
= page
.evaluate(function() {
1152 return $(".address:first").text();
1154 if (actual
!= expected
) {
1155 console
.log("Clicking tab generates incorrect address");
1156 console
.log("Expected: " + expected
);
1157 console
.log("Actual: " + actual
);
1166 // BIP44 derivation path is shown
1168 page
.open(url
, function(status
) {
1170 var expected
= "m/44'/0'/0'/0";
1171 page
.evaluate(function() {
1172 $(".phrase").val("abandon abandon ability");
1173 $(".phrase").trigger("input");
1175 // check the derivation path of the first address
1176 waitForGenerate(function() {
1177 var actual
= page
.evaluate(function() {
1178 return $("#bip44 .path").val();
1180 if (actual
!= expected
) {
1181 console
.log("BIP44 derivation path is incorrect");
1182 console
.log("Expected: " + expected
);
1183 console
.log("Actual: " + actual
);
1191 // BIP44 extended private key is shown
1193 page
.open(url
, function(status
) {
1195 var expected
= "xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG";
1196 page
.evaluate(function() {
1197 $(".phrase").val("abandon abandon ability");
1198 $(".phrase").trigger("input");
1200 // check the BIP44 extended private key
1201 waitForGenerate(function() {
1202 var actual
= page
.evaluate(function() {
1203 return $(".extended-priv-key").val();
1205 if (actual
!= expected
) {
1206 console
.log("BIP44 extended private key is incorrect");
1207 console
.log("Expected: " + expected
);
1208 console
.log("Actual: " + actual
);
1216 // BIP44 extended public key is shown
1218 page
.open(url
, function(status
) {
1220 var expected
= "xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM";
1221 page
.evaluate(function() {
1222 $(".phrase").val("abandon abandon ability");
1223 $(".phrase").trigger("input");
1225 // check the BIP44 extended public key
1226 waitForGenerate(function() {
1227 var actual
= page
.evaluate(function() {
1228 return $(".extended-pub-key").val();
1230 if (actual
!= expected
) {
1231 console
.log("BIP44 extended public key is incorrect");
1232 console
.log("Expected: " + expected
);
1233 console
.log("Actual: " + actual
);
1241 // BIP44 account field changes address list
1243 page
.open(url
, function(status
) {
1245 var expected
= "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
1246 page
.evaluate(function() {
1247 $(".phrase").val("abandon abandon ability");
1248 $(".phrase").trigger("input");
1250 waitForGenerate(function() {
1251 // change the bip44 purpose field to 45
1252 page
.evaluate(function() {
1253 $("#bip44 .account").val("1");
1254 $("#bip44 .account").trigger("input");
1256 waitForGenerate(function() {
1257 // check the address for the new derivation path
1258 var actual
= page
.evaluate(function() {
1259 return $(".address:first").text();
1261 if (actual
!= expected
) {
1262 console
.log("BIP44 account field generates incorrect address");
1263 console
.log("Expected: " + expected
);
1264 console
.log("Actual: " + actual
);
1273 // BIP44 change field changes address list
1275 page
.open(url
, function(status
) {
1277 var expected
= "1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo";
1278 page
.evaluate(function() {
1279 $(".phrase").val("abandon abandon ability");
1280 $(".phrase").trigger("input");
1282 waitForGenerate(function() {
1283 // change the bip44 purpose field to 45
1284 page
.evaluate(function() {
1285 $("#bip44 .change").val("1");
1286 $("#bip44 .change").trigger("input");
1288 waitForGenerate(function() {
1289 // check the address for the new derivation path
1290 var actual
= page
.evaluate(function() {
1291 return $(".address:first").text();
1293 if (actual
!= expected
) {
1294 console
.log("BIP44 change field generates incorrect address");
1295 console
.log("Expected: " + expected
);
1296 console
.log("Actual: " + actual
);
1305 // BIP32 derivation path can be set
1307 page
.open(url
, function(status
) {
1309 var expected
= "16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L";
1310 page
.evaluate(function() {
1311 $(".phrase").val("abandon abandon ability");
1312 $(".phrase").trigger("input");
1315 waitForGenerate(function() {
1316 page
.evaluate(function() {
1317 $("#bip32-tab a").click();
1319 // set the derivation path to m/1
1320 waitForGenerate(function() {
1321 page
.evaluate(function() {
1322 $("#bip32 .path").val("m/1");
1323 $("#bip32 .path").trigger("input");
1325 // check the address is generated correctly
1326 waitForGenerate(function() {
1327 var actual
= page
.evaluate(function() {
1328 return $(".address:first").text();
1330 if (actual
!= expected
) {
1331 console
.log("Custom BIP32 path generates incorrect address");
1332 console
.log("Expected: " + expected
);
1333 console
.log("Actual: " + actual
);
1343 // BIP32 can use hardened derivation paths
1345 page
.open(url
, function(status
) {
1347 var expected
= "14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4";
1348 page
.evaluate(function() {
1349 $(".phrase").val("abandon abandon ability");
1350 $(".phrase").trigger("input");
1353 waitForGenerate(function() {
1354 page
.evaluate(function() {
1355 $("#bip32-tab a").click();
1357 // set the derivation path to m/0'
1358 waitForGenerate(function() {
1359 page
.evaluate(function() {
1360 $("#bip32 .path").val("m/0'");
1361 $("#bip32 .path").trigger("input");
1363 // check the address is generated correctly
1364 waitForGenerate(function() {
1365 var actual
= page
.evaluate(function() {
1366 return $(".address:first").text();
1368 if (actual
!= expected
) {
1369 console
.log("Hardened BIP32 path generates incorrect address");
1370 console
.log("Expected: " + expected
);
1371 console
.log("Actual: " + actual
);
1381 // BIP32 extended private key is shown
1383 page
.open(url
, function(status
) {
1385 var expected
= "xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe";
1386 page
.evaluate(function() {
1387 $(".phrase").val("abandon abandon ability");
1388 $(".phrase").trigger("input");
1391 waitForGenerate(function() {
1392 page
.evaluate(function() {
1393 $("#bip32-tab a").click();
1395 // check the extended private key is generated correctly
1396 waitForGenerate(function() {
1397 var actual
= page
.evaluate(function() {
1398 return $(".extended-priv-key").val();
1400 if (actual
!= expected
) {
1401 console
.log("BIP32 extended private key is incorrect");
1402 console
.log("Expected: " + expected
);
1403 console
.log("Actual: " + actual
);
1412 // BIP32 extended public key is shown
1414 page
.open(url
, function(status
) {
1416 var expected
= "xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P";
1417 page
.evaluate(function() {
1418 $(".phrase").val("abandon abandon ability");
1419 $(".phrase").trigger("input");
1422 waitForGenerate(function() {
1423 page
.evaluate(function() {
1424 $("#bip32-tab a").click();
1426 // check the extended public key is generated correctly
1427 waitForGenerate(function() {
1428 var actual
= page
.evaluate(function() {
1429 return $(".extended-pub-key").val();
1431 if (actual
!= expected
) {
1432 console
.log("BIP32 extended public key is incorrect");
1433 console
.log("Expected: " + expected
);
1434 console
.log("Actual: " + actual
);
1443 // Derivation path is shown in table
1445 page
.open(url
, function(status
) {
1447 var expected
= "m/44'/0'/0'/0/0";
1448 page
.evaluate(function() {
1449 $(".phrase").val("abandon abandon ability");
1450 $(".phrase").trigger("input");
1452 // check for derivation path in table
1453 waitForGenerate(function() {
1454 var actual
= page
.evaluate(function() {
1455 return $(".index:first").text();
1457 if (actual
!= expected
) {
1458 console
.log("Derivation path shown incorrectly in table");
1459 console
.log("Expected: " + expected
);
1460 console
.log("Actual: " + actual
);
1468 // Derivation path for address can be hardened
1470 page
.open(url
, function(status
) {
1472 var expected
= "18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd";
1473 page
.evaluate(function() {
1474 $(".phrase").val("abandon abandon ability");
1475 $(".phrase").trigger("input");
1478 waitForGenerate(function() {
1479 page
.evaluate(function() {
1480 $("#bip32-tab a").click();
1482 waitForGenerate(function() {
1483 // select the hardened addresses option
1484 page
.evaluate(function() {
1485 $(".hardened-addresses").prop("checked", true);
1486 $(".hardened-addresses").trigger("change");
1488 waitForGenerate(function() {
1489 // check the generated address is hardened
1490 var actual
= page
.evaluate(function() {
1491 return $(".address:first").text();
1493 if (actual
!= expected
) {
1494 console
.log("Hardened address is incorrect");
1495 console
.log("Expected: " + expected
);
1496 console
.log("Actual: " + actual
);
1506 // Derivation path visibility can be toggled
1508 page
.open(url
, function(status
) {
1510 page
.evaluate(function() {
1511 $(".phrase").val("abandon abandon ability");
1512 $(".phrase").trigger("input");
1514 waitForGenerate(function() {
1515 // toggle path visibility
1516 page
.evaluate(function() {
1517 $(".index-toggle").click();
1519 // check the path is not visible
1520 var isInvisible
= page
.evaluate(function() {
1521 return $(".index:first span").hasClass("invisible");
1524 console
.log("Toggled derivation path is visible");
1534 page
.open(url
, function(status
) {
1535 var expected
= "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1537 page
.evaluate(function() {
1538 $(".phrase").val("abandon abandon ability").trigger("input");
1541 waitForGenerate(function() {
1542 var actual
= page
.evaluate(function() {
1543 return $(".address:first").text();
1545 if (actual
!= expected
) {
1546 console
.log("Address is not shown");
1547 console
.log("Expected: " + expected
);
1548 console
.log("Got: " + actual
);
1556 // Addresses are shown in order of derivation path
1558 page
.open(url
, function(status
) {
1560 page
.evaluate(function() {
1561 $(".phrase").val("abandon abandon ability").trigger("input");
1563 // get the derivation paths
1564 waitForGenerate(function() {
1565 var paths
= page
.evaluate(function() {
1566 return $(".index").map(function(i
, e
) {
1570 if (paths
.length
!= 20) {
1571 console
.log("Total paths is less than expected: " + paths
.length
);
1574 for (var i
=0; i
<paths
.length
; i
++) {
1575 var expected
= "m/44'/0'/0'/0/" + i
;
1576 var actual
= paths
[i
];
1577 if (actual
!= expected
) {
1578 console
.log("Path " + i
+ " is incorrect");
1579 console
.log("Expected: " + expected
);
1580 console
.log("Actual: " + actual
);
1589 // Address visibility can be toggled
1591 page
.open(url
, function(status
) {
1593 page
.evaluate(function() {
1594 $(".phrase").val("abandon abandon ability");
1595 $(".phrase").trigger("input");
1597 waitForGenerate(function() {
1598 // toggle address visibility
1599 page
.evaluate(function() {
1600 $(".address-toggle").click();
1602 // check the address is not visible
1603 var isInvisible
= page
.evaluate(function() {
1604 return $(".address:first span").hasClass("invisible");
1607 console
.log("Toggled address is visible");
1615 // Public key is shown
1617 page
.open(url
, function(status
) {
1618 var expected
= "033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3";
1620 page
.evaluate(function() {
1621 $(".phrase").val("abandon abandon ability").trigger("input");
1624 waitForGenerate(function() {
1625 var actual
= page
.evaluate(function() {
1626 return $(".pubkey:first").text();
1628 if (actual
!= expected
) {
1629 console
.log("Public key is not shown");
1630 console
.log("Expected: " + expected
);
1631 console
.log("Got: " + actual
);
1639 // Public key visibility can be toggled
1641 page
.open(url
, function(status
) {
1643 page
.evaluate(function() {
1644 $(".phrase").val("abandon abandon ability");
1645 $(".phrase").trigger("input");
1647 waitForGenerate(function() {
1648 // toggle public key visibility
1649 page
.evaluate(function() {
1650 $(".public-key-toggle").click();
1652 // check the public key is not visible
1653 var isInvisible
= page
.evaluate(function() {
1654 return $(".pubkey:first span").hasClass("invisible");
1657 console
.log("Toggled public key is visible");
1665 // Private key is shown
1667 page
.open(url
, function(status
) {
1668 var expected
= "L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE";
1670 page
.evaluate(function() {
1671 $(".phrase").val("abandon abandon ability").trigger("input");
1674 waitForGenerate(function() {
1675 var actual
= page
.evaluate(function() {
1676 return $(".privkey:first").text();
1678 if (actual
!= expected
) {
1679 console
.log("Private key is not shown");
1680 console
.log("Expected: " + expected
);
1681 console
.log("Got: " + actual
);
1689 // Private key visibility can be toggled
1691 page
.open(url
, function(status
) {
1693 page
.evaluate(function() {
1694 $(".phrase").val("abandon abandon ability");
1695 $(".phrase").trigger("input");
1697 waitForGenerate(function() {
1698 // toggle private key visibility
1699 page
.evaluate(function() {
1700 $(".private-key-toggle").click();
1702 // check the private key is not visible
1703 var isInvisible
= page
.evaluate(function() {
1704 return $(".privkey:first span").hasClass("invisible");
1707 console
.log("Toggled private key is visible");
1715 // More addresses can be generated
1717 page
.open(url
, function(status
) {
1719 page
.evaluate(function() {
1720 $(".phrase").val("abandon abandon ability");
1721 $(".phrase").trigger("input");
1723 waitForGenerate(function() {
1724 // generate more addresses
1725 page
.evaluate(function() {
1728 waitForGenerate(function() {
1729 // check there are more addresses
1730 var addressCount
= page
.evaluate(function() {
1731 return $(".address").length
;
1733 if (addressCount
!= 40) {
1734 console
.log("More addresses cannot be generated");
1743 // A custom number of additional addresses can be generated
1745 page
.open(url
, function(status
) {
1747 page
.evaluate(function() {
1748 $(".phrase").val("abandon abandon ability");
1749 $(".phrase").trigger("input");
1751 waitForGenerate(function() {
1752 // get the current number of addresses
1753 var oldAddressCount
= page
.evaluate(function() {
1754 return $(".address").length
;
1756 // set a custom number of additional addresses
1757 page
.evaluate(function() {
1758 $(".rows-to-add").val(1);
1760 // generate more addresses
1761 page
.evaluate(function() {
1764 waitForGenerate(function() {
1765 // check there are the correct number of addresses
1766 var newAddressCount
= page
.evaluate(function() {
1767 return $(".address").length
;
1769 if (newAddressCount
- oldAddressCount
!= 1) {
1770 console
.log("Number of additional addresses cannot be customized");
1771 console
.log(newAddressCount
)
1772 console
.log(oldAddressCount
)
1781 // Additional addresses are shown in order of derivation path
1783 page
.open(url
, function(status
) {
1785 page
.evaluate(function() {
1786 $(".phrase").val("abandon abandon ability").trigger("input");
1788 waitForGenerate(function() {
1789 // generate more addresses
1790 page
.evaluate(function() {
1793 // get the derivation paths
1794 waitForGenerate(function() {
1795 var paths
= page
.evaluate(function() {
1796 return $(".index").map(function(i
, e
) {
1800 if (paths
.length
!= 40) {
1801 console
.log("Total additional paths is less than expected: " + paths
.length
);
1804 for (var i
=0; i
<paths
.length
; i
++) {
1805 var expected
= "m/44'/0'/0'/0/" + i
;
1806 var actual
= paths
[i
];
1807 if (actual
!= expected
) {
1808 console
.log("Path " + i
+ " is not in correct order");
1809 console
.log("Expected: " + expected
);
1810 console
.log("Actual: " + actual
);
1820 // BIP32 root key can be set by the user
1822 page
.open(url
, function(status
) {
1823 var expected
= "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1825 page
.evaluate(function() {
1826 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1828 waitForGenerate(function() {
1829 var actual
= page
.evaluate(function() {
1830 return $(".address:first").text();
1832 if (actual
!= expected
) {
1833 console
.log("Setting BIP32 root key results in wrong address");
1834 console
.log("Expected: " + expected
);
1835 console
.log("Actual: " + actual
);
1843 // Setting BIP32 root key clears the existing phrase, passphrase and seed
1845 page
.open(url
, function(status
) {
1848 page
.evaluate(function() {
1849 $(".phrase").val("A non-blank but invalid value");
1851 // Accept any confirm dialogs
1852 page
.onConfirm = function() {
1856 page
.evaluate(function() {
1857 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1859 waitForGenerate(function() {
1860 var actual
= page
.evaluate(function() {
1861 return $(".phrase").val();
1863 if (actual
!= expected
) {
1864 console
.log("Phrase not cleared when setting BIP32 root key");
1865 console
.log("Expected: " + expected
);
1866 console
.log("Actual: " + actual
);
1874 // Clearing of phrase, passphrase and seed can be cancelled by user
1876 page
.open(url
, function(status
) {
1877 var expected
= "abandon abandon ability";
1879 page
.evaluate(function() {
1880 $(".phrase").val("abandon abandon ability");
1882 // Cancel any confirm dialogs
1883 page
.onConfirm = function() {
1887 page
.evaluate(function() {
1888 $(".root-key").val("xprv9s21ZrQH143K3d3vzEDD3KpSKmxsZ3y7CqhAL1tinwtP6wqK4TKEKjpBuo6P2hUhB6ZENo7TTSRytiP857hBZVpBdk8PooFuRspE1eywwNZ").trigger("input");
1890 var actual
= page
.evaluate(function() {
1891 return $(".phrase").val();
1893 if (actual
!= expected
) {
1894 console
.log("Phrase not retained when cancelling changes to BIP32 root key");
1895 console
.log("Expected: " + expected
);
1896 console
.log("Actual: " + actual
);
1903 // Custom BIP32 root key is used when changing the derivation path
1905 page
.open(url
, function(status
) {
1906 var expected
= "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
1908 page
.evaluate(function() {
1909 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1911 waitForGenerate(function() {
1912 // change the derivation path
1913 page
.evaluate(function() {
1914 $("#account").val("1").trigger("input");
1916 // check the bip32 root key is used for derivation, not the blank phrase
1917 waitForGenerate(function() {
1918 var actual
= page
.evaluate(function() {
1919 return $(".address:first").text();
1921 if (actual
!= expected
) {
1922 console
.log("Changing the derivation path does not use BIP32 root key");
1923 console
.log("Expected: " + expected
);
1924 console
.log("Actual: " + actual
);
1933 // Incorrect mnemonic shows error
1935 page
.open(url
, function(status
) {
1937 page
.evaluate(function() {
1938 $(".phrase").val("abandon abandon abandon").trigger("input");
1940 waitForFeedback(function() {
1941 // check there is an error shown
1942 var feedback
= page
.evaluate(function() {
1943 return $(".feedback").text();
1945 if (feedback
.length
<= 0) {
1946 console
.log("Invalid mnemonic does not show error");
1954 // Incorrect word shows suggested replacement
1956 page
.open(url
, function(status
) {
1958 page
.evaluate(function() {
1959 $(".phrase").val("abandon abandon abiliti").trigger("input");
1961 // check there is a suggestion shown
1962 waitForFeedback(function() {
1963 var feedback
= page
.evaluate(function() {
1964 return $(".feedback").text();
1966 if (feedback
.indexOf("did you mean ability?") < 0) {
1967 console
.log("Incorrect word does not show suggested replacement");
1968 console
.log("Error: " + error
);
1976 // Github pull request 48
1977 // First four letters of word shows that word, not closest
1978 // since first four letters gives unique word in BIP39 wordlist
1979 // eg ille should show illegal, not idle
1981 page
.open(url
, function(status
) {
1982 // set the incomplete word
1983 page
.evaluate(function() {
1984 $(".phrase").val("ille").trigger("input");
1986 // check there is a suggestion shown
1987 waitForFeedback(function() {
1988 var feedback
= page
.evaluate(function() {
1989 return $(".feedback").text();
1991 if (feedback
.indexOf("did you mean illegal?") < 0) {
1992 console
.log("Start of word does not show correct suggestion");
1993 console
.log("Error: " + error
);
2001 // Incorrect BIP32 root key shows error
2003 page
.open(url
, function(status
) {
2005 page
.evaluate(function() {
2006 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj").trigger("input");
2008 // check there is an error shown
2009 waitForFeedback(function() {
2010 var feedback
= page
.evaluate(function() {
2011 return $(".feedback").text();
2013 if (feedback
!= "Invalid root key") {
2014 console
.log("Invalid root key does not show error");
2015 console
.log("Error: " + error
);
2023 // Derivation path not starting with m shows error
2025 page
.open(url
, function(status
) {
2026 // set the mnemonic phrase
2027 page
.evaluate(function() {
2028 $(".phrase").val("abandon abandon ability").trigger("input");
2030 waitForGenerate(function() {
2031 // select the bip32 tab so custom derivation path can be set
2032 page
.evaluate(function() {
2033 $("#bip32-tab a").click();
2035 waitForGenerate(function() {
2036 // set the incorrect derivation path
2037 page
.evaluate(function() {
2038 $("#bip32 .path").val("n/0").trigger("input");
2040 waitForFeedback(function() {
2041 var feedback
= page
.evaluate(function() {
2042 return $(".feedback").text();
2044 if (feedback
!= "First character must be 'm'") {
2045 console
.log("Derivation path not starting with m should show error");
2046 console
.log("Error: " + error
);
2056 // Derivation path containing invalid characters shows useful error
2058 page
.open(url
, function(status
) {
2059 // set the mnemonic phrase
2060 page
.evaluate(function() {
2061 $(".phrase").val("abandon abandon ability").trigger("input");
2063 waitForGenerate(function() {
2064 // select the bip32 tab so custom derivation path can be set
2065 page
.evaluate(function() {
2066 $("#bip32-tab a").click();
2068 waitForGenerate(function() {
2069 // set the incorrect derivation path
2070 page
.evaluate(function() {
2071 $("#bip32 .path").val("m/1/0wrong1/1").trigger("input");
2073 waitForFeedback(function() {
2074 var feedback
= page
.evaluate(function() {
2075 return $(".feedback").text();
2077 if (feedback
!= "Invalid characters 0wrong1 found at depth 2") {
2078 console
.log("Derivation path with invalid characters should show error");
2079 console
.log("Error: " + error
);
2089 // Github Issue 11: Default word length is 15
2090 // https://github.com/iancoleman/bip39/issues/11
2092 page
.open(url
, function(status
) {
2093 // get the word length
2094 var defaultLength
= page
.evaluate(function() {
2095 return $(".strength").val();
2097 if (defaultLength
!= 15) {
2098 console
.log("Default word length is not 15");
2106 // Github Issue 12: Generate more rows with private keys hidden
2107 // https://github.com/iancoleman/bip39/issues/12
2109 page
.open(url
, function(status
) {
2111 page
.evaluate(function() {
2112 $(".phrase").val("abandon abandon ability");
2113 $(".phrase").trigger("input");
2115 waitForGenerate(function() {
2116 // toggle private keys hidden, then generate more addresses
2117 page
.evaluate(function() {
2118 $(".private-key-toggle").click();
2121 waitForGenerate(function() {
2122 // check more have been generated
2124 var numPrivKeys
= page
.evaluate(function() {
2125 return $(".privkey").length
;
2127 if (numPrivKeys
!= expected
) {
2128 console
.log("Wrong number of addresses when clicking 'more' with hidden privkeys");
2129 console
.log("Expected: " + expected
);
2130 console
.log("Actual: " + numPrivKeys
);
2133 // check no private keys are shown
2134 var numHiddenPrivKeys
= page
.evaluate(function() {
2135 return $(".privkey span[class=invisible]").length
;
2137 if (numHiddenPrivKeys
!= expected
) {
2138 console
.log("Generating more does not retain hidden state of privkeys");
2139 console
.log("Expected: " + expected
);
2140 console
.log("Actual: " + numHiddenPrivKeys
);
2149 // Github Issue 19: Mnemonic is not sensitive to whitespace
2150 // https://github.com/iancoleman/bip39/issues/19
2152 page
.open(url
, function(status
) {
2154 var expected
= "xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC";
2155 page
.evaluate(function() {
2156 var doubleSpace
= " ";
2157 $(".phrase").val("urge cat" + doubleSpace
+ "bid");
2158 $(".phrase").trigger("input");
2160 waitForGenerate(function() {
2161 // Check the bip32 root key is correct
2162 var actual
= page
.evaluate(function() {
2163 return $(".root-key").val();
2165 if (actual
!= expected
) {
2166 console
.log("Mnemonic is sensitive to whitespace");
2167 console
.log("Expected: " + expected
);
2168 console
.log("Actual: " + actual
);
2176 // Github Issue 23: Part 1: Use correct derivation path when changing tabs
2177 // https://github.com/iancoleman/bip39/issues/23
2179 page
.open(url
, function(status
) {
2180 // 1) and 2) set the phrase
2181 page
.evaluate(function() {
2182 $(".phrase").val("abandon abandon ability").trigger("input");
2184 waitForGenerate(function() {
2185 // 3) select bip32 tab
2186 page
.evaluate(function() {
2187 $("#bip32-tab a").click();
2189 waitForGenerate(function() {
2190 // 4) switch from bitcoin to litecoin
2191 page
.evaluate(function() {
2192 $(".network option").filter(function() {
2193 return $(this).html() == "LTC - Litecoin";
2194 }).prop("selected", true);
2195 $(".network").trigger("change");
2197 waitForGenerate(function() {
2198 // 5) Check derivation path is displayed correctly
2199 var expected
= "m/0/0";
2200 var actual
= page
.evaluate(function() {
2201 return $(".index:first").text();
2203 if (actual
!= expected
) {
2204 console
.log("Github Issue 23 Part 1: derivation path display error");
2205 console
.log("Expected: " + expected
);
2206 console
.log("Actual: " + actual
);
2209 // 5) Check address is displayed correctly
2210 var expected
= "LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5";
2211 var actual
= page
.evaluate(function() {
2212 return $(".address:first").text();
2214 if (actual
!= expected
) {
2215 console
.log("Github Issue 23 Part 1: address display error");
2216 console
.log("Expected: " + expected
);
2217 console
.log("Actual: " + actual
);
2227 // Github Issue 23 Part 2: Coin selection in derivation path
2228 // https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920
2230 page
.open(url
, function(status
) {
2232 page
.evaluate(function() {
2233 $(".phrase").val("abandon abandon ability").trigger("input");
2235 waitForGenerate(function() {
2236 // switch from bitcoin to clam
2237 page
.evaluate(function() {
2238 $(".network option").filter(function() {
2239 return $(this).html() == "CLAM - Clams";
2240 }).prop("selected", true);
2241 $(".network").trigger("change");
2243 waitForGenerate(function() {
2244 // check derivation path is displayed correctly
2245 var expected
= "m/44'/23'/0'/0/0";
2246 var actual
= page
.evaluate(function() {
2247 return $(".index:first").text();
2249 if (actual
!= expected
) {
2250 console
.log("Github Issue 23 Part 2: Coin in BIP44 derivation path is incorrect");
2251 console
.log("Expected: " + expected
);
2252 console
.log("Actual: " + actual
);
2261 // Github Issue 26: When using a Root key derrived altcoins are incorrect
2262 // https://github.com/iancoleman/bip39/issues/26
2264 page
.open(url
, function(status
) {
2265 // 1) 2) and 3) set the root key
2266 page
.evaluate(function() {
2267 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
2269 waitForGenerate(function() {
2270 // 4) switch from bitcoin to viacoin
2271 page
.evaluate(function() {
2272 $(".network option").filter(function() {
2273 return $(this).html() == "VIA - Viacoin";
2274 }).prop("selected", true);
2275 $(".network").trigger("change");
2277 waitForGenerate(function() {
2278 // 5) ensure the derived address is correct
2279 var expected
= "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
2280 var actual
= page
.evaluate(function() {
2281 return $(".address:first").text();
2283 if (actual
!= expected
) {
2284 console
.log("Github Issue 26: address is incorrect when changing networks and using root-key to derive");
2285 console
.log("Expected: " + expected
);
2286 console
.log("Actual: " + actual
);
2295 // Selecting a language with no existing phrase should generate a phrase in
2298 page
.open(url
, function(status
) {
2299 // Select a language
2300 // Need to manually simulate hash being set due to quirk between
2301 // 'click' event triggered by javascript vs triggered by mouse.
2302 // Perhaps look into page.sendEvent
2303 // http://phantomjs.org/api/webpage/method/send-event.html
2304 page
.evaluate(function() {
2305 window
.location
.hash
= "#japanese";
2306 $("a[href='#japanese']").trigger("click");
2308 waitForGenerate(function() {
2309 // Check the mnemonic is in Japanese
2310 var phrase
= page
.evaluate(function() {
2311 return $(".phrase").val();
2313 if (phrase
.length
<= 0) {
2314 console
.log("No Japanese phrase generated");
2317 if (phrase
.charCodeAt(0) < 128) {
2318 console
.log("First character of Japanese phrase is ascii");
2319 console
.log("Phrase: " + phrase
);
2327 // Selecting a language with existing phrase should update the phrase to use
2330 page
.open(url
, function(status
) {
2331 // Set the phrase to an English phrase.
2332 page
.evaluate(function() {
2333 $(".phrase").val("abandon abandon ability").trigger("input");
2335 waitForGenerate(function() {
2336 // Change to Italian
2337 // Need to manually simulate hash being set due to quirk between
2338 // 'click' event triggered by javascript vs triggered by mouse.
2339 // Perhaps look into page.sendEvent
2340 // http://phantomjs.org/api/webpage/method/send-event.html
2341 page
.evaluate(function() {
2342 window
.location
.hash
= "#italian";
2343 $("a[href='#italian']").trigger("click");
2345 waitForGenerate(function() {
2346 // Check only the language changes, not the phrase
2347 var expected
= "abaco abaco abbaglio";
2348 var actual
= page
.evaluate(function() {
2349 return $(".phrase").val();
2351 if (actual
!= expected
) {
2352 console
.log("Changing language with existing phrase");
2353 console
.log("Expected: " + expected
);
2354 console
.log("Actual: " + actual
);
2357 // Check the address is correct
2358 var expected
= "1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV";
2359 var actual
= page
.evaluate(function() {
2360 return $(".address:first").text();
2362 if (actual
!= expected
) {
2363 console
.log("Changing language generates incorrect address");
2364 console
.log("Expected: " + expected
);
2365 console
.log("Actual: " + actual
);
2374 // Suggested replacement for erroneous word in non-English language
2376 page
.open(url
, function(status
) {
2377 // Set an incorrect phrase in Italian
2378 page
.evaluate(function() {
2379 $(".phrase").val("abaco abaco zbbaglio").trigger("input");
2381 waitForFeedback(function() {
2382 // Check the suggestion is correct
2383 var feedback
= page
.evaluate(function() {
2384 return $(".feedback").text();
2386 if (feedback
.indexOf("did you mean abbaglio?") < 0) {
2387 console
.log("Incorrect Italian word does not show suggested replacement");
2388 console
.log("Error: " + error
);
2397 // Japanese word does not break across lines.
2399 // https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
2401 page
.open(url
, function(status
) {
2402 hasWordBreakCss
= page
.content
.indexOf("word-break: keep-all;") > -1;
2403 if (!hasWordBreakCss
) {
2404 console
.log("Japanese words can break across lines mid-word");
2405 console
.log("Check CSS for '.phrase { word-break: keep-all; }'");
2408 // Run the next test
2413 // Language can be specified at page load using hash value in url
2415 page
.open(url
, function(status
) {
2416 // Set the page hash as if it were on a fresh page load
2417 page
.evaluate(function() {
2418 window
.location
.hash
= "#japanese";
2420 // Generate a random phrase
2421 page
.evaluate(function() {
2422 $(".generate").trigger("click");
2424 waitForGenerate(function() {
2425 // Check the phrase is in Japanese
2426 var phrase
= page
.evaluate(function() {
2427 return $(".phrase").val();
2429 if (phrase
.length
<= 0) {
2430 console
.log("No phrase generated using url hash");
2433 if (phrase
.charCodeAt(0) < 128) {
2434 console
.log("Language not detected from url hash on page load.");
2435 console
.log("Phrase: " + phrase
);
2443 // Entropy unit tests
2445 page
.open(url
, function(status
) {
2446 var response
= page
.evaluate(function() {
2448 // binary entropy is detected
2450 e
= Entropy
.fromString("01010101");
2451 if (e
.base
.str
!= "binary") {
2452 return "Binary entropy not detected correctly";
2458 // base6 entropy is detected
2460 e
= Entropy
.fromString("012345012345");
2461 if (e
.base
.str
!= "base 6") {
2462 return "base6 entropy not detected correctly";
2468 // dice entropy is detected
2470 e
= Entropy
.fromString("123456123456");
2471 if (e
.base
.str
!= "base 6 (dice)") {
2472 return "dice entropy not detected correctly";
2478 // base10 entropy is detected
2480 e
= Entropy
.fromString("0123456789");
2481 if (e
.base
.str
!= "base 10") {
2482 return "base10 entropy not detected correctly";
2488 // hex entropy is detected
2490 e
= Entropy
.fromString("0123456789ABCDEF");
2491 if (e
.base
.str
!= "hexadecimal") {
2492 return "hexadecimal entropy not detected correctly";
2498 // card entropy is detected
2500 e
= Entropy
.fromString("AC4DTHKS");
2501 if (e
.base
.str
!= "card") {
2502 return "card entropy not detected correctly";
2508 // entropy is case insensitive
2510 e
= Entropy
.fromString("aBcDeF");
2511 if (e
.cleanStr
!= "aBcDeF") {
2512 return "Entropy should not be case sensitive";
2518 // dice entropy is converted to base6
2520 e
= Entropy
.fromString("123456");
2521 if (e
.cleanStr
!= "123450") {
2522 return "Dice entropy is not automatically converted to base6";
2528 // dice entropy is preferred to base6 if ambiguous
2530 e
= Entropy
.fromString("12345");
2531 if (e
.base
.str
!= "base 6 (dice)") {
2532 return "dice not used as default over base 6";
2538 // unused characters are ignored
2540 e
= Entropy
.fromString("fghijkl");
2541 if (e
.cleanStr
!= "f") {
2542 return "additional characters are not ignored";
2548 // the lowest base is used by default
2549 // 7 could be decimal or hexadecimal, but should be detected as decimal
2551 e
= Entropy
.fromString("7");
2552 if (e
.base
.str
!= "base 10") {
2553 return "lowest base is not used";
2559 // Leading zeros are retained
2561 e
= Entropy
.fromString("000A");
2562 if (e
.cleanStr
!= "000A") {
2563 return "Leading zeros are not retained";
2569 // Leading zeros are correctly preserved for hex in binary string
2571 e
= Entropy
.fromString("2A");
2572 if (e
.binaryStr
!= "00101010") {
2573 return "Hex leading zeros are not correct in binary";
2579 // Leading zeros for base 6 as binary string
2580 // 20 = 2 events at 2.58 bits per event = 5 bits
2581 // 20 in base 6 = 12 in base 10 = 1100 in base 2
2582 // so it needs 1 bit of padding to be the right bit length
2584 e
= Entropy
.fromString("20");
2585 if (e
.binaryStr
!= "01100") {
2586 return "Base 6 as binary has leading zeros";
2592 // Leading zeros for base 10 as binary string
2594 e
= Entropy
.fromString("17");
2595 if (e
.binaryStr
!= "010001") {
2596 return "Base 10 as binary has leading zeros";
2602 // Leading zeros for card entropy as binary string.
2603 // Card entropy is hashed so 2c does not necessarily produce leading zeros.
2605 e
= Entropy
.fromString("2c");
2606 if (e
.binaryStr
!= "0010") {
2607 return "Card entropy as binary has leading zeros";
2613 // Keyboard mashing results in weak entropy
2614 // Despite being a long string, it's less than 30 bits of entropy
2616 e
= Entropy
.fromString("aj;se ifj; ask,dfv js;ifj");
2617 if (e
.binaryStr
.length
>= 30) {
2618 return "Keyboard mashing should produce weak entropy";
2624 // Card entropy is used if every pair could be a card
2626 e
= Entropy
.fromString("4c3c2c");
2627 if (e
.base
.str
!= "card") {
2628 return "Card entropy not used if all pairs are cards";
2634 // Card entropy uses base 52
2635 // [ cards, binary ]
2639 [ "acqs", "11011100" ],
2640 [ "acks", "01011100" ],
2641 [ "2cac", "11111000" ],
2654 [ "ks2c", "01010100" ],
2655 [ "KS2C", "01010100" ],
2657 for (var i
=0; i
<cards
.length
; i
++) {
2658 var card
= cards
[i
][0];
2659 var result
= cards
[i
][1];
2660 e
= Entropy
.fromString(card
);
2661 console
.log(e
.binary
+ " " + result
);
2662 if (e
.binaryStr
!== result
) {
2663 return "card entropy " + card
+ " not parsed correctly: " + result
+ " != " + e
.binaryStr
;
2672 if (response
!= "PASS") {
2673 console
.log("Entropy unit tests");
2674 console
.log(response
);
2681 // Entropy can be entered by the user
2683 page
.open(url
, function(status
) {
2685 mnemonic: "abandon abandon ability",
2686 address: "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug",
2689 page
.evaluate(function() {
2690 $(".use-entropy").prop("checked", true).trigger("change");
2691 $(".entropy").val("00000000 00000000 00000000 00000000").trigger("input");
2693 // check the mnemonic is set and address is correct
2694 waitForGenerate(function() {
2695 var actual
= page
.evaluate(function() {
2697 address: $(".address:first").text(),
2698 mnemonic: $(".phrase").val(),
2701 if (actual
.mnemonic
!= expected
.mnemonic
) {
2702 console
.log("Entropy does not generate correct mnemonic");
2703 console
.log("Expected: " + expected
.mnemonic
);
2704 console
.log("Got: " + actual
.mnemonic
);
2707 if (actual
.address
!= expected
.address
) {
2708 console
.log("Entropy does not generate correct address");
2709 console
.log("Expected: " + expected
.address
);
2710 console
.log("Got: " + actual
.address
);
2718 // A warning about entropy is shown to the user, with additional information
2720 page
.open(url
, function(status
) {
2721 // get text content from entropy sections of page
2722 var hasWarning
= page
.evaluate(function() {
2723 var entropyText
= $(".entropy-container").text();
2724 var warning
= "mnemonic may be insecure";
2725 if (entropyText
.indexOf(warning
) == -1) {
2728 var readMoreText
= $("#entropy-notes").parent().text();
2729 var goodSources
= "flipping a fair coin, rolling a fair dice, noise measurements etc";
2730 if (readMoreText
.indexOf(goodSources
) == -1) {
2735 // check the warnings and information are shown
2737 console
.log("Page does not contain warning about using own entropy");
2744 // The types of entropy available are described to the user
2746 page
.open(url
, function(status
) {
2747 // get placeholder text for entropy field
2748 var placeholder
= page
.evaluate(function() {
2749 return $(".entropy").attr("placeholder");
2759 for (var i
=0; i
<options
.length
; i
++) {
2760 var option
= options
[i
];
2761 if (placeholder
.indexOf(option
) == -1) {
2762 console
.log("Available entropy type is not shown to user: " + option
);
2770 // The actual entropy used is shown to the user
2772 page
.open(url
, function(status
) {
2774 var badEntropySource
= page
.evaluate(function() {
2775 var entropy
= "Not A Very Good Entropy Source At All";
2776 $(".use-entropy").prop("checked", true).trigger("change");
2777 $(".entropy").val(entropy
).trigger("input");
2779 // check the actual entropy being used is shown
2780 waitForEntropyFeedback(function() {
2781 var expectedText
= "AedEceAA";
2782 var entropyText
= page
.evaluate(function() {
2783 return $(".entropy-container").text();
2785 if (entropyText
.indexOf(expectedText
) == -1) {
2786 console
.log("Actual entropy used is not shown");
2794 // Binary entropy can be entered
2796 page
.open(url
, function(status
) {
2798 page
.evaluate(function() {
2799 $(".use-entropy").prop("checked", true).trigger("change");
2800 $(".entropy").val("01").trigger("input");
2802 // check the entropy is shown to be the correct type
2803 waitForEntropyFeedback(function() {
2804 var entropyText
= page
.evaluate(function() {
2805 return $(".entropy-container").text();
2807 if (entropyText
.indexOf("binary") == -1) {
2808 console
.log("Binary entropy is not detected and presented to user");
2816 // Base 6 entropy can be entered
2818 page
.open(url
, function(status
) {
2820 page
.evaluate(function() {
2821 $(".use-entropy").prop("checked", true).trigger("change");
2822 $(".entropy").val("012345").trigger("input");
2824 // check the entropy is shown to be the correct type
2825 waitForEntropyFeedback(function() {
2826 var entropyText
= page
.evaluate(function() {
2827 return $(".entropy-container").text();
2829 if (entropyText
.indexOf("base 6") == -1) {
2830 console
.log("Base 6 entropy is not detected and presented to user");
2838 // Base 6 dice entropy can be entered
2840 page
.open(url
, function(status
) {
2842 page
.evaluate(function() {
2843 $(".use-entropy").prop("checked", true).trigger("change");
2844 $(".entropy").val("123456").trigger("input");
2846 // check the entropy is shown to be the correct type
2847 waitForEntropyFeedback(function() {
2848 var entropyText
= page
.evaluate(function() {
2849 return $(".entropy-container").text();
2851 if (entropyText
.indexOf("dice") == -1) {
2852 console
.log("Dice entropy is not detected and presented to user");
2860 // Base 10 entropy can be entered
2862 page
.open(url
, function(status
) {
2864 page
.evaluate(function() {
2865 $(".use-entropy").prop("checked", true).trigger("change");
2866 $(".entropy").val("789").trigger("input");
2868 // check the entropy is shown to be the correct type
2869 waitForEntropyFeedback(function() {
2870 var entropyText
= page
.evaluate(function() {
2871 return $(".entropy-container").text();
2873 if (entropyText
.indexOf("base 10") == -1) {
2874 console
.log("Base 10 entropy is not detected and presented to user");
2882 // Hexadecimal entropy can be entered
2884 page
.open(url
, function(status
) {
2886 page
.evaluate(function() {
2887 $(".use-entropy").prop("checked", true).trigger("change");
2888 $(".entropy").val("abcdef").trigger("input");
2890 // check the entropy is shown to be the correct type
2891 waitForEntropyFeedback(function() {
2892 var entropyText
= page
.evaluate(function() {
2893 return $(".entropy-container").text();
2895 if (entropyText
.indexOf("hexadecimal") == -1) {
2896 console
.log("Hexadecimal entropy is not detected and presented to user");
2904 // Dice entropy value is shown as the converted base 6 value
2906 page
.open(url
, function(status
) {
2908 page
.evaluate(function() {
2909 $(".use-entropy").prop("checked", true).trigger("change");
2910 $(".entropy").val("123456").trigger("input");
2912 // check the entropy is shown as base 6, not as the original dice value
2913 waitForEntropyFeedback(function() {
2914 var entropyText
= page
.evaluate(function() {
2915 return $(".entropy-container").text();
2917 if (entropyText
.indexOf("123450") == -1) {
2918 console
.log("Dice entropy is not shown to user as base 6 value");
2921 if (entropyText
.indexOf("123456") > -1) {
2922 console
.log("Dice entropy value is shown instead of true base 6 value");
2930 // The number of bits of entropy accumulated is shown
2932 page
.open(url
, function(status
) {
2935 [ "0000 0000 0000 0000 0000", "20" ],
2938 [ "6", "2" ], // 6 in card is 0 in base 6, 0 in base 6 is 2.6 bits (rounded down to 2 bits)
2939 [ "7", "3" ], // 7 in base 10 is 111 in base 2, no leading zeros
2944 [ "1A", "8" ], // hex is always multiple of 4 bits of entropy
2951 [ "6666", "10" ], // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of 2.58 bits, which is 10.32 bits (rounded down to 10 bits)
2952 [ "2227", "13" ], // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded down to 13)
2955 [ "0000101017", "33" ], // 10 events at 3.32 bits per event
2956 [ "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "225" ], // cards are not replaced, so a full deck is not 52^52 entropy which is 296 bits, it's 52!, which is 225 bits
2959 page
.evaluate(function(e
) {
2960 $(".use-entropy").prop("checked", true).trigger("change");
2963 var nextTest
= function runNextTest(i
) {
2964 var entropy
= tests
[i
][0];
2965 var expected
= tests
[i
][1];
2967 page
.evaluate(function(e
) {
2968 $(".entropy").val(e
).trigger("input");
2970 // check the number of bits of entropy is shown
2971 waitForEntropyFeedback(function() {
2972 var entropyText
= page
.evaluate(function() {
2973 return $(".entropy-container").text();
2975 if (entropyText
.replace(/\s/g,"").indexOf("Bits" + expected
) == -1) {
2976 console
.log("Accumulated entropy is not shown correctly for " + entropy
);
2979 var isLastTest
= i
== tests
.length
- 1;
2992 // There is feedback provided about the supplied entropy
2994 page
.open(url
, function(status
) {
2999 type: "hexadecimal",
3003 strength: "less than a second",
3006 entropy: "AAAAAAAA",
3007 filtered: "AAAAAAAA",
3008 type: "hexadecimal",
3012 strength: "less than a second - Repeats like \"aaa\" are easy to guess",
3015 entropy: "AAAAAAAA B",
3016 filtered: "AAAAAAAAB",
3017 type: "hexadecimal",
3021 strength: "less than a second - Repeats like \"aaa\" are easy to guess",
3024 entropy: "AAAAAAAA BBBBBBBB",
3025 filtered: "AAAAAAAABBBBBBBB",
3026 type: "hexadecimal",
3030 strength: "less than a second - Repeats like \"aaa\" are easy to guess",
3033 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
3034 filtered: "AAAAAAAABBBBBBBBCCCCCCCC",
3035 type: "hexadecimal",
3039 strength: "less than a second",
3042 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
3043 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD",
3044 type: "hexadecimal",
3048 strength: "2 minutes",
3051 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA",
3052 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDA",
3053 type: "hexadecimal",
3060 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE",
3061 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEE",
3062 type: "hexadecimal",
3066 strength: "3 years",
3069 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE FFFFFFFF",
3070 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEEFFFFFFFF",
3071 type: "hexadecimal",
3075 strength: "centuries",
3083 strength: "less than a second",
3086 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
3087 type: "card (full deck)",
3091 strength: "centuries",
3094 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d",
3095 type: "card (full deck, 1 duplicate: 3d)",
3099 strength: "centuries",
3102 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d",
3103 type: "card (2 duplicates: 3d 4d, 1 missing: KS)",
3107 strength: "centuries",
3110 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d",
3111 type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)",
3115 strength: "centuries",
3117 // Next test was throwing uncaught error in zxcvbn
3118 // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2
3120 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
3121 type: "card (full deck, 52 duplicates: ac 2c 3c...)",
3125 strength: "centuries",
3127 // Case insensitivity to duplicate cards
3130 type: "card (1 duplicate: AS)",
3134 strength: "less than a second",
3138 type: "card (1 duplicate: as)",
3142 strength: "less than a second",
3144 // Missing cards are detected
3146 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
3147 type: "card (1 missing: 9C)",
3151 strength: "centuries",
3154 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
3155 type: "card (2 missing: 9C 5D)",
3159 strength: "centuries",
3162 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
3163 type: "card (4 missing: 9C 5D QD...)",
3167 strength: "centuries",
3169 // More than six missing cards does not show message
3171 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks",
3176 strength: "centuries",
3178 // Multiple decks of cards increases bits per event
3198 entropy: "3d3d3d3d",
3204 entropy: "3d3d3d3d3d",
3210 entropy: "3d3d3d3d3d3d",
3216 entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d",
3220 strength: 'less than a second - Repeats like "abcabcabc" are only slightly harder to guess than "abc"',
3224 page
.evaluate(function() {
3225 $(".use-entropy").prop("checked", true).trigger("change");
3227 var nextTest
= function runNextTest(i
) {
3228 function getFeedbackError(expected
, actual
) {
3229 if ("filtered" in expected
&& actual
.indexOf(expected
.filtered
) == -1) {
3230 return "Filtered value not in feedback";
3232 if ("type" in expected
&& actual
.indexOf(expected
.type
) == -1) {
3233 return "Entropy type not in feedback";
3235 if ("events" in expected
&& actual
.indexOf(expected
.events
) == -1) {
3236 return "Event count not in feedback";
3238 if ("bits" in expected
&& actual
.indexOf(expected
.bits
) == -1) {
3239 return "Bit count not in feedback";
3241 if ("strength" in expected
&& actual
.indexOf(expected
.strength
) == -1) {
3242 return "Strength not in feedback";
3244 if ("bitsPerEvent" in expected
&& actual
.indexOf(expected
.bitsPerEvent
) == -1) {
3245 return "bitsPerEvent not in feedback";
3250 page
.evaluate(function(e
) {
3251 $(".addresses").empty();
3252 $(".phrase").val("");
3253 $(".entropy").val(e
).trigger("input");
3255 waitForEntropyFeedback(function() {
3256 var mnemonic
= page
.evaluate(function() {
3257 return $(".phrase").val();
3259 // Check mnemonic length
3260 if ("words" in test
&& test
.words
== 0) {
3261 if (mnemonic
.length
> 0) {
3262 console
.log("Mnemonic length for " + test
.strength
+ " strength is not " + test
.words
);
3263 console
.log("Entropy: " + test
.entropy
);
3264 console
.log("Mnemonic: " + mnemonic
);
3268 else if ("words" in test
) {
3269 if (mnemonic
.split(" ").length
!= test
.words
) {
3270 console
.log("Mnemonic length for " + test
.strength
+ " strength is not " + test
.words
);
3271 console
.log("Entropy: " + test
.entropy
);
3272 console
.log("Mnemonic: " + mnemonic
);
3277 var feedback
= page
.evaluate(function() {
3278 return $(".entropy-container").text();
3280 var feedbackError
= getFeedbackError(test
, feedback
);
3281 if (feedbackError
) {
3282 console
.log("Entropy feedback for " + test
.entropy
+ " returned error");
3283 console
.log(feedbackError
);
3287 var isLastTest
= i
== tests
.length
- 1;
3300 // Entropy is truncated from the left
3302 page
.open(url
, function(status
) {
3303 var expected
= "avocado zoo zone";
3305 page
.evaluate(function() {
3306 $(".use-entropy").prop("checked", true).trigger("change");
3307 var entropy
= "00000000 00000000 00000000 00000000";
3308 entropy
+= "11111111 11111111 11111111 1111"; // Missing last byte
3309 $(".entropy").val(entropy
).trigger("input");
3311 // check the entropy is truncated from the right
3312 waitForGenerate(function() {
3313 var actual
= page
.evaluate(function() {
3314 return $(".phrase").val();
3316 if (actual
!= expected
) {
3317 console
.log("Entropy is not truncated from the right");
3318 console
.log("Expected: " + expected
);
3319 console
.log("Got: " + actual
);
3327 // Very large entropy results in very long mnemonics
3329 page
.open(url
, function(status
) {
3331 page
.evaluate(function() {
3332 $(".use-entropy").prop("checked", true).trigger("change");
3334 // Generate a very long entropy string
3335 for (var i
=0; i
<33; i
++) {
3336 entropy
+= "AAAAAAAA"; // 3 words * 33 iterations = 99 words
3338 $(".entropy").val(entropy
).trigger("input");
3340 // check the mnemonic is very long
3341 waitForGenerate(function() {
3342 var wordCount
= page
.evaluate(function() {
3343 return $(".phrase").val().split(" ").length
;
3345 if (wordCount
!= 99) {
3346 console
.log("Large entropy does not generate long mnemonic");
3347 console
.log("Expected 99 words, got " + wordCount
);
3355 // Is compatible with bip32jp entropy
3356 // https://bip32jp.github.io/english/index.html
3358 // Is incompatible with:
3361 page
.open(url
, function(status
) {
3362 var expected
= "train then jungle barely whip fiber purpose puppy eagle cloud clump hospital robot brave balcony utility detect estate old green desk skill multiply virus";
3364 page
.evaluate(function() {
3365 $(".use-entropy").prop("checked", true).trigger("change");
3366 var entropy
= "543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543";
3367 $(".entropy").val(entropy
).trigger("input");
3369 // check the mnemonic matches the expected value from bip32jp
3370 waitForGenerate(function() {
3371 var actual
= page
.evaluate(function() {
3372 return $(".phrase").val();
3374 if (actual
!= expected
) {
3375 console
.log("Mnemonic does not match bip32jp for base 6 entropy");
3376 console
.log("Expected: " + expected
);
3377 console
.log("Got: " + actual
);
3385 // Blank entropy does not generate mnemonic or addresses
3387 page
.open(url
, function(status
) {
3389 page
.evaluate(function() {
3390 $(".use-entropy").prop("checked", true).trigger("change");
3391 $(".entropy").val("").trigger("input");
3393 waitForFeedback(function() {
3394 // check there is no mnemonic
3395 var phrase
= page
.evaluate(function() {
3396 return $(".phrase").val();
3399 console
.log("Blank entropy does not result in blank mnemonic");
3400 console
.log("Got: " + phrase
);
3403 // check there are no addresses displayed
3404 var addresses
= page
.evaluate(function() {
3405 return $(".address").length
;
3407 if (addresses
!= 0) {
3408 console
.log("Blank entropy does not result in zero addresses");
3411 // Check the feedback says 'blank entropy'
3412 var feedback
= page
.evaluate(function() {
3413 return $(".feedback").text();
3415 if (feedback
!= "Blank entropy") {
3416 console
.log("Blank entropy does not show feedback message");
3424 // Mnemonic length can be selected even for weak entropy
3426 page
.open(url
, function(status
) {
3428 page
.evaluate(function() {
3429 $(".use-entropy").prop("checked", true).trigger("change");
3430 $(".entropy").val("012345");
3431 $(".mnemonic-length").val("18").trigger("change");
3433 // check the mnemonic is the correct length
3434 waitForGenerate(function() {
3435 var phrase
= page
.evaluate(function() {
3436 return $(".phrase").val();
3438 var numberOfWords
= phrase
.split(/\s/g).length
;
3439 if (numberOfWords
!= 18) {
3440 console
.log("Weak entropy cannot be overridden to give 18 word mnemonic");
3441 console
.log(phrase
);
3450 // https://github.com/iancoleman/bip39/issues/33
3451 // Final cards should contribute entropy
3453 page
.open(url
, function(status
) {
3455 page
.evaluate(function() {
3456 $(".use-entropy").prop("checked", true).trigger("change");
3457 $(".entropy").val("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").trigger("input");
3460 waitForGenerate(function() {
3461 var originalPhrase
= page
.evaluate(function() {
3462 return $(".phrase").val();
3464 // Set the last 12 cards to be AS
3465 page
.evaluate(function() {
3466 $(".addresses").empty();
3467 $(".entropy").val("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").trigger("input");
3469 // get the new mnemonic
3470 waitForGenerate(function() {
3471 var newPhrase
= page
.evaluate(function() {
3472 return $(".phrase").val();
3474 // check the phrase has changed
3475 if (newPhrase
== originalPhrase
) {
3476 console
.log("Changing last 12 cards does not change mnemonic");
3477 console
.log("Original:");
3478 console
.log(originalPhrase
);
3479 console
.log("New:");
3480 console
.log(newPhrase
);
3490 // https://github.com/iancoleman/bip39/issues/35
3493 page
.open(url
, function(status
) {
3495 page
.evaluate(function() {
3496 $(".generate").click();
3498 waitForGenerate(function() {
3499 var p
= page
.evaluate(function() {
3500 // get position of mnemonic element
3501 return $(".phrase").offset();
3503 p
.top
= Math
.ceil(p
.top
);
3504 p
.left
= Math
.ceil(p
.left
);
3505 // check the qr code shows
3506 page
.sendEvent("mousemove", p
.left
+4, p
.top
+4);
3507 var qrShowing
= page
.evaluate(function() {
3508 return $(".qr-container").find("canvas").length
> 0;
3511 console
.log("QR Code does not show");
3514 // check the qr code hides
3515 page
.sendEvent("mousemove", p
.left
-4, p
.top
-4);
3516 var qrHidden
= page
.evaluate(function() {
3517 return $(".qr-container").find("canvas").length
== 0;
3520 console
.log("QR Code does not hide");
3528 // BIP44 account extendend private key is shown
3529 // github issue 37 - compatibility with electrum
3531 page
.open(url
, function(status
) {
3533 var expected
= "xprv9yzrnt4zWVJUr1k2VxSPy9ettKz5PpeDMgaVG7UKedhqnw1tDkxP2UyYNhuNSumk2sLE5ctwKZs9vwjsq3e1vo9egCK6CzP87H2cVYXpfwQ";
3534 page
.evaluate(function() {
3535 $(".phrase").val("abandon abandon ability");
3536 $(".phrase").trigger("input");
3538 // check the BIP44 account extended private key
3539 waitForGenerate(function() {
3540 var actual
= page
.evaluate(function() {
3541 return $("#bip44 .account-xprv").val();
3543 if (actual
!= expected
) {
3544 console
.log("BIP44 account extended private key is incorrect");
3545 console
.log("Expected: " + expected
);
3546 console
.log("Actual: " + actual
);
3554 // BIP44 account extendend public key is shown
3555 // github issue 37 - compatibility with electrum
3557 page
.open(url
, function(status
) {
3559 var expected
= "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3560 page
.evaluate(function() {
3561 $(".phrase").val("abandon abandon ability");
3562 $(".phrase").trigger("input");
3564 // check the BIP44 account extended public key
3565 waitForGenerate(function() {
3566 var actual
= page
.evaluate(function() {
3567 return $("#bip44 .account-xpub").val();
3569 if (actual
!= expected
) {
3570 console
.log("BIP44 account extended public key is incorrect");
3571 console
.log("Expected: " + expected
);
3572 console
.log("Actual: " + actual
);
3581 // BIP32 root key can be set as an xpub
3583 page
.open(url
, function(status
) {
3585 page
.evaluate(function() {
3586 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3587 var bip44AccountXpub
= "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3588 $("#root-key").val(bip44AccountXpub
);
3589 $("#root-key").trigger("input");
3591 waitForFeedback(function() {
3592 page
.evaluate(function() {
3594 $("#bip32-tab a").click();
3596 waitForGenerate(function() {
3597 page
.evaluate(function() {
3598 // derive external addresses for this xpub
3599 var firstAccountDerivationPath
= "m/0";
3600 $("#bip32-path").val(firstAccountDerivationPath
);
3601 $("#bip32-path").trigger("input");
3603 waitForGenerate(function() {
3604 // check the addresses are generated
3605 var expected
= "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
3606 var actual
= page
.evaluate(function() {
3607 return $(".address:first").text();
3609 if (actual
!= expected
) {
3610 console
.log("xpub key does not generate addresses in table");
3611 console
.log("Expected: " + expected
);
3612 console
.log("Actual: " + actual
);
3615 // check the xprv key is not set
3616 var expected
= "NA";
3617 var actual
= page
.evaluate(function() {
3618 return $(".extended-priv-key").val();
3620 if (actual
!= expected
) {
3621 console
.log("xpub key as root shows derived bip32 xprv key");
3622 console
.log("Expected: " + expected
);
3623 console
.log("Actual: " + actual
);
3626 // check the private key is not set
3627 var expected
= "NA";
3628 var actual
= page
.evaluate(function() {
3629 return $(".privkey:first").text();
3631 if (actual
!= expected
) {
3632 console
.log("xpub key generates private key in addresses table");
3633 console
.log("Expected: " + expected
);
3634 console
.log("Actual: " + actual
);
3645 // xpub for bip32 root key will not work with hardened derivation paths
3647 page
.open(url
, function(status
) {
3649 page
.evaluate(function() {
3650 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3651 var bip44AccountXpub
= "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3652 $("#root-key").val(bip44AccountXpub
);
3653 $("#root-key").trigger("input");
3655 waitForFeedback(function() {
3656 // Check feedback is correct
3657 var expected
= "Hardened derivation path is invalid with xpub key";
3658 var actual
= page
.evaluate(function() {
3659 return $(".feedback").text();
3661 if (actual
!= expected
) {
3662 console
.log("xpub key with hardened derivation path does not show feedback");
3663 console
.log("Expected: " + expected
);
3664 console
.log("Actual: " + actual
);
3667 // Check no addresses are shown
3669 var actual
= page
.evaluate(function() {
3670 return $(".addresses tr").length
;
3672 if (actual
!= expected
) {
3673 console
.log("addresses still show after setting xpub key with hardened derivation path");
3674 console
.log("Expected: " + expected
);
3675 console
.log("Actual: " + actual
);
3684 // no root key shows feedback
3686 page
.open(url
, function(status
) {
3687 // click the bip32 tab on fresh page
3688 page
.evaluate(function() {
3689 $("#bip32-tab a").click();
3691 waitForFeedback(function() {
3692 // Check feedback is correct
3693 var expected
= "No root key";
3694 var actual
= page
.evaluate(function() {
3695 return $(".feedback").text();
3697 if (actual
!= expected
) {
3698 console
.log("Blank root key not detected");
3699 console
.log("Expected: " + expected
);
3700 console
.log("Actual: " + actual
);
3709 // display error switching tabs while addresses are generating
3711 page
.open(url
, function(status
) {
3713 page
.evaluate(function() {
3714 $(".phrase").val("abandon abandon ability").trigger("input");
3716 waitForGenerate(function() {
3717 // set to generate 500 more addresses
3718 // generate more addresses
3719 // change tabs which should cancel the previous generating
3720 page
.evaluate(function() {
3721 $(".rows-to-add").val("100");
3723 $("#bip32-tab a").click();
3725 // check the derivation paths are in order and of the right quantity
3726 waitForGenerate(function() {
3727 var paths
= page
.evaluate(function() {
3728 return $(".index").map(function(i
, e
) {
3732 for (var i
=0; i
<paths
.length
; i
++) {
3733 var expected
= "m/0/" + i
;
3734 var actual
= paths
[i
];
3735 if (actual
!= expected
) {
3736 console
.log("Path " + i
+ " is not in correct order");
3737 console
.log("Expected: " + expected
);
3738 console
.log("Actual: " + actual
);
3742 if (paths
.length
!= 20) {
3743 console
.log("Generation was not cancelled by new action");
3753 // padding for binary should give length with multiple of 256
3754 // hashed entropy 1111 is length 252, so requires 4 leading zeros
3755 // prior to issue 49 it would only generate 2 leading zeros, ie missing 2
3757 page
.open(url
, function(status
) {
3758 expected
= "avocado valid quantum cross link predict excuse edit street able flame large galaxy ginger nuclear"
3760 page
.evaluate(function() {
3761 $(".use-entropy").prop("checked", true).trigger("change");
3762 $(".mnemonic-length").val("15");
3763 $(".entropy").val("1111").trigger("input");
3765 waitForGenerate(function() {
3767 var actual
= page
.evaluate(function() {
3768 return $(".phrase").val();
3770 // check the mnemonic is correct
3771 if (actual
!= expected
) {
3772 console
.log("Left padding error for entropy");
3773 console
.log("Expected: " + expected
);
3774 console
.log("Actual: " + actual
);
3782 // Github pull request 55
3783 // https://github.com/iancoleman/bip39/pull/55
3786 page
.open(url
, function(status
) {
3787 // set mnemonic and select bip32 tab
3788 page
.evaluate(function() {
3789 $("#bip32-tab a").click();
3790 $(".phrase").val("abandon abandon ability").trigger("input");
3792 waitForGenerate(function() {
3794 // set bip32 client to bitcoin core
3795 page
.evaluate(function() {
3796 var bitcoinCoreIndex
= "0";
3797 $("#bip32-client").val(bitcoinCoreIndex
).trigger("change");
3799 waitForGenerate(function() {
3800 // get the derivation path
3801 var actual
= page
.evaluate(function() {
3802 return $("#bip32-path").val();
3804 // check the derivation path is correct
3805 expected
= "m/0'/0'"
3806 if (actual
!= expected
) {
3807 console
.log("Selecting Bitcoin Core client does not set correct derivation path");
3808 console
.log("Expected: " + expected
);
3809 console
.log("Actual: " + actual
);
3812 // get hardened addresses
3813 var usesHardenedAddresses
= page
.evaluate(function() {
3814 return $(".hardened-addresses").prop("checked");
3816 // check hardened addresses is selected
3817 if(!usesHardenedAddresses
) {
3818 console
.log("Selecting Bitcoin Core client does not use hardened addresses");
3821 // check input is readonly
3822 var pathIsReadonly
= page
.evaluate(function() {
3823 return $("#bip32-path").prop("readonly");
3825 if (!pathIsReadonly
) {
3826 console
.log("Selecting Bitcoin Core client does not set derivation path to readonly");
3830 // set bip32 client to multibit
3831 page
.evaluate(function() {
3832 var multibitIndex
= "2";
3833 $("#bip32-client").val(multibitIndex
).trigger("change");
3835 waitForGenerate(function() {
3836 // get the derivation path
3837 var actual
= page
.evaluate(function() {
3838 return $("#bip32-path").val();
3840 // check the derivation path is correct
3842 if (actual
!= expected
) {
3843 console
.log("Selecting Multibit client does not set correct derivation path");
3844 console
.log("Expected: " + expected
);
3845 console
.log("Actual: " + actual
);
3848 // get hardened addresses
3849 var usesHardenedAddresses
= page
.evaluate(function() {
3850 return $(".hardened-addresses").prop("checked");
3852 // check hardened addresses is selected
3853 if(usesHardenedAddresses
) {
3854 console
.log("Selecting Multibit client does not uncheck hardened addresses");
3857 // CUSTOM DERIVATION PATH
3858 // check input is not readonly
3859 page
.evaluate(function() {
3860 $("#bip32-client").val("custom").trigger("change");
3862 // do not wait for generate, since there is no change to the
3863 // derivation path there is no new generation performed
3864 var pathIsReadonly
= page
.evaluate(function() {
3865 return $("#bip32-path").prop("readonly");
3867 if (pathIsReadonly
) {
3868 console
.log("Selecting Custom Derivation Path does not allow derivation path input");
3879 // https://github.com/iancoleman/bip39/issues/58
3880 // bip32 derivation is correct, does not drop leading zeros
3882 // https://medium.com/@alexberegszaszi/why-do-my-bip32-wallets-disagree-6f3254cc5846
3884 page
.open(url
, function(status
) {
3885 // set the phrase and passphrase
3886 var expected
= "17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F";
3887 // Note that bitcore generates an incorrect address
3888 // 13EuKhffWkBE2KUwcbkbELZb1MpzbimJ3Y
3889 // see the medium.com link above for more details
3890 page
.evaluate(function() {
3891 $(".phrase").val("fruit wave dwarf banana earth journey tattoo true farm silk olive fence");
3892 $(".passphrase").val("banana").trigger("input");
3894 // check the address is generated correctly
3895 waitForGenerate(function() {
3896 var actual
= page
.evaluate(function() {
3897 return $(".address:first").text();
3899 if (actual
!= expected
) {
3900 console
.log("BIP32 derivation is incorrect");
3901 console
.log("Expected: " + expected
);
3902 console
.log("Actual: " + actual
);
3912 // Japanese mnemonics generate incorrect bip32 seed
3913 // BIP39 seed is set from phrase
3915 page
.open(url
, function(status
) {
3917 var expected
= "a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55";
3918 page
.evaluate(function() {
3919 $(".phrase").val("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら");
3920 $("#passphrase").val("メートルガバヴァぱばぐゞちぢ十人十色");
3921 $("#passphrase").trigger("input");
3923 // check the seed is generated correctly
3924 waitForGenerate(function() {
3925 var actual
= page
.evaluate(function() {
3926 return $(".seed").val();
3928 if (actual
!= expected
) {
3929 console
.log("BIP39 seed is incorrectly generated from Japanese mnemonic");
3930 console
.log("Expected: " + expected
);
3931 console
.log("Actual: " + actual
);
3939 // BIP49 official test vectors
3940 // https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki#test-vectors
3942 page
.open(url
, function(status
) {
3943 // set the phrase and select bitcoin testnet
3944 var expected
= "2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2";
3945 page
.evaluate(function() {
3946 $("#bip49-tab a").click();
3947 $(".phrase").val("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about");
3948 $(".network option[selected]").removeAttr("selected");
3949 $(".network option").filter(function() {
3950 return $(this).html() == "BTC - Bitcoin Testnet";
3951 }).prop("selected", true);
3952 $(".network").trigger("change");
3953 $(".phrase").trigger("input");
3955 // check the first address
3956 waitForGenerate(function() {
3957 var actual
= page
.evaluate(function() {
3958 return $(".address:first").text();
3960 if (actual
!= expected
) {
3961 console
.log("BIP49 address is incorrect");
3962 console
.log("Expected: " + expected
);
3963 console
.log("Actual: " + actual
);
3971 // BIP49 derivation path is shown
3973 page
.open(url
, function(status
) {
3975 var expected
= "m/49'/0'/0'/0";
3976 page
.evaluate(function() {
3977 $("#bip49-tab a").click();
3978 $(".phrase").val("abandon abandon ability").trigger("input");
3980 // check the derivation path of the first address
3981 waitForGenerate(function() {
3982 var actual
= page
.evaluate(function() {
3983 return $("#bip49 .path").val();
3985 if (actual
!= expected
) {
3986 console
.log("BIP49 derivation path is incorrect");
3987 console
.log("Expected: " + expected
);
3988 console
.log("Actual: " + actual
);
3996 // BIP49 extended private key is shown
3998 page
.open(url
, function(status
) {
4000 var expected
= "xprvA1hukYsW7QfX9CVsaDAKde4eryajKa4DKWb6m9YjSnqkiZHrahFwwTJfEQTwBQ5kptWT5pZMkkusT1oK8dc1efQ8VFfq4SLSPAWd7Cpt423";
4001 page
.evaluate(function() {
4002 $("#bip49-tab a").click();
4003 $(".phrase").val("abandon abandon ability").trigger("input");
4005 // check the BIP49 extended private key
4006 waitForGenerate(function() {
4007 var actual
= page
.evaluate(function() {
4008 return $(".extended-priv-key").val();
4010 if (actual
!= expected
) {
4011 console
.log("BIP49 extended private key is incorrect");
4012 console
.log("Expected: " + expected
);
4013 console
.log("Actual: " + actual
);
4021 // BIP49 extended public key is shown
4023 page
.open(url
, function(status
) {
4025 var expected
= "xpub6EhGA4QPwnDpMgaLgEhKzn1PR1RDj2n4gjWhZXxM18NjbMd18EaCVFd95gkLARJaBD2rXAYJED2gdkUbGn1KkrSzCKR554AdABUELoainnt";
4026 page
.evaluate(function() {
4027 $("#bip49-tab a").click();
4028 $(".phrase").val("abandon abandon ability").trigger("input");
4030 // check the BIP49 extended public key
4031 waitForGenerate(function() {
4032 var actual
= page
.evaluate(function() {
4033 return $(".extended-pub-key").val();
4035 if (actual
!= expected
) {
4036 console
.log("BIP49 extended public key is incorrect");
4037 console
.log("Expected: " + expected
);
4038 console
.log("Actual: " + actual
);
4046 // BIP49 account field changes address list
4048 page
.open(url
, function(status
) {
4050 var expected
= "381wg1GGN4rP88rNC9v7QWsiww63yLVPsn";
4051 page
.evaluate(function() {
4052 $("#bip49-tab a").click();
4053 $(".phrase").val("abandon abandon ability").trigger("input");
4055 waitForGenerate(function() {
4056 // change the bip49 account field to 1
4057 page
.evaluate(function() {
4058 $("#bip49 .account").val("1");
4059 $("#bip49 .account").trigger("input");
4061 waitForGenerate(function() {
4062 // check the address for the new derivation path
4063 var actual
= page
.evaluate(function() {
4064 return $(".address:first").text();
4066 if (actual
!= expected
) {
4067 console
.log("BIP49 account field generates incorrect address");
4068 console
.log("Expected: " + expected
);
4069 console
.log("Actual: " + actual
);
4078 // BIP49 change field changes address list
4080 page
.open(url
, function(status
) {
4082 var expected
= "3PEM7MiKed5konBoN66PQhK8r3hjGhy9dT";
4083 page
.evaluate(function() {
4084 $("#bip49-tab a").click();
4085 $(".phrase").val("abandon abandon ability").trigger("input");
4087 waitForGenerate(function() {
4088 // change the bip49 change field to 1
4089 page
.evaluate(function() {
4090 $("#bip49 .change").val("1");
4091 $("#bip49 .change").trigger("input");
4093 waitForGenerate(function() {
4094 // check the address for the new derivation path
4095 var actual
= page
.evaluate(function() {
4096 return $(".address:first").text();
4098 if (actual
!= expected
) {
4099 console
.log("BIP49 change field generates incorrect address");
4100 console
.log("Expected: " + expected
);
4101 console
.log("Actual: " + actual
);
4110 // BIP49 account extendend private key is shown
4112 page
.open(url
, function(status
) {
4114 var expected
= "xprv9y3uhgQbfQZbj3o98nfgLDwGGuCJjUn7GKArSAZXjKgMjSdYHjQmTyf78s22g6jsGrxXvHB6HJeFyvFSPkuYZajeTGMZVXV6aNLWw2fagCn";
4115 page
.evaluate(function() {
4116 $("#bip49-tab a").click();
4117 $(".phrase").val("abandon abandon ability");
4118 $(".phrase").trigger("input");
4120 // check the BIP49 account extended private key
4121 waitForGenerate(function() {
4122 var actual
= page
.evaluate(function() {
4123 return $("#bip49 .account-xprv").val();
4125 if (actual
!= expected
) {
4126 console
.log("BIP49 account extended private key is incorrect");
4127 console
.log("Expected: " + expected
);
4128 console
.log("Actual: " + actual
);
4136 // BIP49 account extendend public key is shown
4138 page
.open(url
, function(status
) {
4140 var expected
= "xpub6C3G7BwVVn7twXscEpCghMszpw2o8wVxdY6TEYy9HfDLcExgqGj21myazAiq6HSmW2F1cBiFqJa3D1cqcDpSh8pbZF5x4iqpd4PyJvd3gjB";
4141 page
.evaluate(function() {
4142 $("#bip49-tab a").click();
4143 $(".phrase").val("abandon abandon ability");
4144 $(".phrase").trigger("input");
4146 // check the BIP49 account extended public key
4147 waitForGenerate(function() {
4148 var actual
= page
.evaluate(function() {
4149 return $("#bip49 .account-xpub").val();
4151 if (actual
!= expected
) {
4152 console
.log("BIP49 account extended public key is incorrect");
4153 console
.log("Expected: " + expected
);
4154 console
.log("Actual: " + actual
);
4162 // Test selecting coin where bip49 is unavailable (eg CLAM)
4164 page
.open(url
, function(status
) {
4166 page
.evaluate(function() {
4167 $("#bip49-tab a").click();
4168 $(".phrase").val("abandon abandon ability");
4169 $(".phrase").trigger("input");
4171 waitForGenerate(function() {
4172 // select non-bip49 network, ie CLAM network
4173 page
.evaluate(function() {
4174 $(".network option[selected]").removeAttr("selected");
4175 $(".network option").filter(function() {
4176 return $(this).html() == "CLAM - Clams";
4177 }).prop("selected", true);
4178 $(".network").trigger("change");
4180 // check the BIP49 error is shown
4181 var bip49ErrorShown
= page
.evaluate(function() {
4182 var bip49hidden
= $("#bip49 .available").hasClass("hidden");
4183 bip49hidden
= bip49hidden
&& !($("#bip49 .unavailable").hasClass("hidden"));
4186 if (!bip49ErrorShown
) {
4187 console
.log("BIP49 error not shown for non-bip49 network");
4190 // check there are no addresses shown
4191 var addressCount
= page
.evaluate(function() {
4192 return $(".address").length
;
4194 if (addressCount
!= 0) {
4195 console
.log("BIP49 address count for non-bip49 network is " + addressCount
);
4198 // check the derived keys are blank
4199 var areBlank
= page
.evaluate(function() {
4200 var prvKeyIsBlank
= $(".extended-priv-key").val().length
== 0;
4201 var pubKeyIsBlank
= $(".extended-pub-key").val().length
== 0;
4202 return prvKeyIsBlank
&& pubKeyIsBlank
;
4205 console
.log("BIP49 extended keys for non-bip49 network are not blank ");
4214 // Cleared mnemonic and root key still allows addresses to be generated
4215 // https://github.com/iancoleman/bip39/issues/43
4217 page
.open(url
, function(status
) {
4219 page
.evaluate(function() {
4220 $("#bip49-tab a").click();
4221 $(".phrase").val("abandon abandon ability");
4222 $(".phrase").trigger("input");
4224 waitForGenerate(function() {
4225 // clear the mnemonic and root key
4226 page
.evaluate(function() {
4227 $(".phrase").val("");
4228 $(".phrase").trigger("input");
4229 $(".root-key").val("");
4230 $(".root-key").trigger("input");
4233 waitForFeedback(function() {
4234 // check there are no addresses shown
4235 var addressCount
= page
.evaluate(function() {
4236 return $(".address").length
;
4238 if (addressCount
!= 0) {
4239 console
.log("Clearing mnemonic should not allow addresses to be generated");
4249 // error trying to generate addresses from xpub with hardened derivation
4251 page
.open(url
, function(status
) {
4253 page
.evaluate(function() {
4254 // Use bip32 tab with hardened addresses
4255 $(".hardened-addresses").prop("checked", true);
4256 $("#bip32-tab a").click();
4257 // set xpub for account 0 of bip44 for 'abandon abandon ability'
4258 var bip44AccountXpub
= "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
4259 $("#root-key").val(bip44AccountXpub
);
4260 $("#root-key").trigger("input");
4262 waitForFeedback(function() {
4263 // check the error message shows
4264 var expected
= "Hardened derivation path is invalid with xpub key";
4265 var actual
= page
.evaluate(function() {
4266 return $(".feedback").text();
4268 if (actual
!= expected
) {
4269 console
.log("xpub key with hardened addresses does not show feedback");
4270 console
.log("Expected: " + expected
);
4271 console
.log("Actual: " + actual
);
4279 // Litecoin uses xprv by default, and can optionally be set to ltpv
4281 // https://github.com/iancoleman/bip39/issues/96
4282 // Issue with extended keys on Litecoin
4284 page
.open(url
, function(status
) {
4285 // set the phrase and coin
4286 page
.evaluate(function() {
4287 $(".phrase").val("abandon abandon ability");
4288 $(".network option[selected]").removeAttr("selected");
4289 $(".network option").filter(function() {
4290 return $(this).html() == "LTC - Litecoin";
4291 }).prop("selected", true);
4292 $(".network").trigger("change");
4293 $(".phrase").trigger("input");
4295 // check the extended key is generated correctly
4296 waitForGenerate(function() {
4297 var expected
= "xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi";
4298 var actual
= page
.evaluate(function() {
4299 return $(".root-key").val();
4301 if (actual
!= expected
) {
4302 console
.log("Litecoin root key does not default to xprv");
4303 console
.log("Expected: " + expected
);
4304 console
.log("Actual: " + actual
);
4307 // set litecoin to use ltub
4308 page
.evaluate(function() {
4309 $(".addresses").empty();
4310 $(".litecoin-use-ltub").prop("checked", true);
4311 $(".litecoin-use-ltub").trigger("change");
4313 waitForGenerate(function() {
4314 var expected
= "Ltpv71G8qDifUiNesiPqf6h5V6eQ8ic77oxQiYtawiACjBEx3sTXNR2HGDGnHETYxESjqkMLFBkKhWVq67ey1B2MKQXannUqNy1RZVHbmrEjnEU";
4315 var actual
= page
.evaluate(function() {
4316 return $(".root-key").val();
4318 if (actual
!= expected
) {
4319 console
.log("Litecoin root key cannot be set to use ltub");
4320 console
.log("Expected: " + expected
);
4321 console
.log("Actual: " + actual
);
4330 // BIP32 tab can use P2WPKH Nested In P2SH
4331 // github issue 91 part 2
4332 // https://github.com/iancoleman/bip39/issues/91
4333 // generate new addresses from xpub?
4335 page
.open(url
, function(status
) {
4336 // set the xpub and coin and select bip32 tab with p2wpkh addresses
4337 page
.evaluate(function() {
4338 // use p2wpkh addresses
4339 $(".p2wpkh-nested-in-p2sh").prop("checked", true);
4341 $("#bip32-tab a").click();
4343 $(".network option[selected]").removeAttr("selected");
4344 $(".network option").filter(function() {
4345 return $(this).html() == "BTC - Bitcoin Testnet";
4346 }).prop("selected", true);
4347 $(".network").trigger("change");
4348 // Set root xpub to BIP49 official test vector account 0
4349 $(".root-key").val("tpubDD7tXK8KeQ3YY83yWq755fHY2JW8Ha8Q765tknUM5rSvjPcGWfUppDFMpQ1ScziKfW3ZNtZvAD7M3u7bSs7HofjTD3KP3YxPK7X6hwV8Rk2");
4350 $(".root-key").trigger("input");
4352 // check the address is generated correctly
4353 waitForGenerate(function() {
4354 var expected
= "2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2";
4355 var actual
= page
.evaluate(function() {
4356 return $(".address:first").text();
4358 if (actual
!= expected
) {
4359 console
.log("BIP32 tab cannot generate P2WPKH Nested In P2SH addresses");
4360 console
.log("Expected: " + expected
);
4361 console
.log("Actual: " + actual
);
4370 // https://github.com/iancoleman/bip39/issues/99#issuecomment-327094159
4371 // "warn me emphatically when they have detected invalid input" to the entropy field
4372 // A warning is shown when entropy is filtered and discarded
4374 page
.open(url
, function(status
) {
4376 page
.evaluate(function() {
4377 $(".use-entropy").prop("checked", true).trigger("change");
4378 $(".entropy").val("00000000 00000000 00000000 00000000").trigger("input");
4380 // check the filter warning does not show
4381 waitForGenerate(function() {
4382 var warningIsHidden
= page
.evaluate(function() {
4383 return $(".entropy-container .filter-warning").hasClass("hidden");
4385 if (!warningIsHidden
) {
4386 console
.log("Entropy filter warning is showing when it should not");
4389 page
.evaluate(function() {
4390 $(".entropy").val("10000000 zxcvbn 00000000 00000000 00000000").trigger("input");
4392 // check the filter warning shows
4393 waitForEntropyFeedback(function() {
4394 var warningIsHidden
= page
.evaluate(function() {
4395 return $(".entropy-container .filter-warning").hasClass("hidden");
4397 if (warningIsHidden
) {
4398 console
.log("Entropy filter warning is not showing when it should");
4407 // Bitcoin Cash address can be set to use bitpay format
4409 page
.open(url
, function(status
) {
4410 // set the phrase and coin and address format
4411 var expected
= "CZnpA9HPmvhuhLLPWJP8rNDpLUYXy1LXFk";
4412 page
.evaluate(function() {
4413 $(".use-bitpay-addresses").prop("checked", true);
4414 $(".phrase").val("abandon abandon ability");
4415 $(".phrase").trigger("input");
4416 $(".network option[selected]").removeAttr("selected");
4417 $(".network option").filter(function() {
4418 return $(this).html() == "BCH - Bitcoin Cash";
4419 }).prop("selected", true);
4420 $(".network").trigger("change");
4422 // check the address is generated correctly
4423 waitForGenerate(function() {
4424 var actual
= page
.evaluate(function() {
4425 return $(".address:first").text();
4427 if (actual
!= expected
) {
4428 console
.log("Bitcoin Cash address is incorrect");
4429 console
.log("Expected: " + expected
);
4430 console
.log("Actual: " + actual
);
4438 // If you wish to add more tests, do so here...
4440 // Here is a blank test template
4444 page.open(url, function(status) {
4445 // Do something on the page
4446 page.evaluate(function() {
4447 $(".phrase").val("abandon abandon ability").trigger("input");
4449 waitForGenerate(function() {
4450 // Check the result of doing the thing
4451 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
4452 var actual = page.evaluate(function() {
4453 return $(".address:first").text();
4455 if (actual != expected) {
4456 console.log("A specific message about what failed");
4457 console.log("Expected: " + expected);
4458 console.log("Actual: " + actual);
4461 // Run the next test
4471 console
.log("Running tests...");
4472 tests
= shuffle(tests
);