]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blob - tests.js
Test additional addresses ordering
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / tests.js
1 // Usage:
2 // $ phantomjs tests.js
3
4
5 var page = require('webpage').create();
6 var url = 'src/index.html';
7 var testMaxTime = 5000;
8
9 page.onResourceError = function(e) {
10 console.log("Error loading " + e.url);
11 phantom.exit();
12 }
13
14 function fail() {
15 console.log("Failed");
16 phantom.exit();
17 }
18
19 function waitForGenerate(fn, maxTime) {
20 if (!maxTime) {
21 maxTime = testMaxTime;
22 }
23 var start = new Date().getTime();
24 var prevAddressCount = -1;
25 var wait = function keepWaiting() {
26 var now = new Date().getTime();
27 var hasTimedOut = now - start > maxTime;
28 var addressCount = page.evaluate(function() {
29 return $(".address").length;
30 });
31 var hasFinished = addressCount > 0 && addressCount == prevAddressCount;
32 prevAddressCount = addressCount;
33 if (hasFinished) {
34 fn();
35 }
36 else if (hasTimedOut) {
37 console.log("Test timed out");
38 fn();
39 }
40 else {
41 setTimeout(keepWaiting, 100);
42 }
43 }
44 wait();
45 }
46
47 function next() {
48 if (tests.length > 0) {
49 var testsStr = tests.length == 1 ? "test" : "tests";
50 console.log(tests.length + " " + testsStr + " remaining");
51 tests.shift()();
52 }
53 else {
54 console.log("Finished with 0 failures");
55 phantom.exit();
56 }
57 }
58
59 /**
60 * Randomize array element order in-place.
61 * Using Durstenfeld shuffle algorithm.
62 * See http://stackoverflow.com/a/12646864
63 */
64 function shuffle(array) {
65 for (var i = array.length - 1; i > 0; i--) {
66 var j = Math.floor(Math.random() * (i + 1));
67 var temp = array[i];
68 array[i] = array[j];
69 array[j] = temp;
70 }
71 return array;
72 }
73
74 tests = [
75
76 // Page loads with status of 'success'
77 function() {
78 page.open(url, function(status) {
79 if (status != "success") {
80 console.log("Page did not load with status 'success'");
81 fail();
82 }
83 next();
84 });
85 },
86
87 // Page has text
88 function() {
89 page.open(url, function(status) {
90 var content = page.evaluate(function() {
91 return document.body.textContent.trim();
92 });
93 if (!content) {
94 console.log("Page does not have text");
95 fail();
96 }
97 next();
98 });
99 },
100
101 // Entering mnemonic generates addresses
102 function() {
103 page.open(url, function(status) {
104 // set the phrase
105 page.evaluate(function() {
106 $(".phrase").val("abandon abandon ability").trigger("input");
107 });
108 // get the address
109 waitForGenerate(function() {
110 var addressCount = page.evaluate(function() {
111 return $(".address").length;
112 });
113 if (addressCount != 20) {
114 console.log("Mnemonic did not generate addresses");
115 console.log("Expected: " + expected);
116 console.log("Got: " + actual);
117 fail();
118 }
119 next();
120 });
121 });
122 },
123
124 // Random button generates random mnemonic
125 function() {
126 page.open(url, function(status) {
127 // check initial phrase is empty
128 var phrase = page.evaluate(function() {
129 return $(".phrase").text();
130 });
131 if (phrase != "") {
132 console.log("Initial phrase is not blank");
133 fail();
134 }
135 // press the 'generate' button
136 page.evaluate(function() {
137 $(".generate").click();
138 });
139 // get the new phrase
140 waitForGenerate(function() {
141 var phrase = page.evaluate(function() {
142 return $(".phrase").val();
143 });
144 if (phrase.length <= 0) {
145 console.log("Phrase not generated by pressing button");
146 fail();
147 }
148 next();
149 });
150 });
151 },
152
153 // Mnemonic length can be customized
154 function() {
155 page.open(url, function(status) {
156 // set the length to 6
157 var expectedLength = "6";
158 page.evaluate(function() {
159 $(".strength option[selected]").removeAttr("selected");
160 $(".strength option[value=6]").prop("selected", true);
161 });
162 // press the 'generate' button
163 page.evaluate(function() {
164 $(".generate").click();
165 });
166 // check the new phrase is six words long
167 waitForGenerate(function() {
168 var actualLength = page.evaluate(function() {
169 var words = $(".phrase").val().split(" ");
170 return words.length;
171 });
172 if (actualLength != expectedLength) {
173 console.log("Phrase not generated with correct length");
174 console.log("Expected: " + expectedLength);
175 console.log("Actual: " + actualLength);
176 fail();
177 }
178 next();
179 });
180 });
181 },
182
183 // Passphrase can be set
184 function() {
185 page.open(url, function(status) {
186 // set the phrase and passphrase
187 var expected = "15pJzUWPGzR7avffV9nY5by4PSgSKG9rba";
188 page.evaluate(function() {
189 $(".phrase").val("abandon abandon ability");
190 $(".passphrase").val("secure_passphrase").trigger("input");
191 });
192 // check the address is generated correctly
193 waitForGenerate(function() {
194 var actual = page.evaluate(function() {
195 return $(".address:first").text();
196 });
197 if (actual != expected) {
198 console.log("Passphrase results in wrong address");
199 console.log("Expected: " + expected);
200 console.log("Actual: " + actual);
201 fail();
202 }
203 next();
204 });
205 });
206 },
207
208 // Network can be set to bitcoin testnet
209 function() {
210 page.open(url, function(status) {
211 // set the phrase and coin
212 var expected = "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi";
213 page.evaluate(function() {
214 $(".phrase").val("abandon abandon ability");
215 $(".phrase").trigger("input");
216 $(".network option[selected]").removeAttr("selected");
217 $(".network option[value=1]").prop("selected", true);
218 $(".network").trigger("change");
219 });
220 // check the address is generated correctly
221 waitForGenerate(function() {
222 var actual = page.evaluate(function() {
223 return $(".address:first").text();
224 });
225 if (actual != expected) {
226 console.log("Bitcoin testnet address is incorrect");
227 console.log("Expected: " + expected);
228 console.log("Actual: " + actual);
229 fail();
230 }
231 next();
232 });
233 });
234 },
235
236 // Network can be set to litecoin
237 function() {
238 page.open(url, function(status) {
239 // set the phrase and coin
240 var expected = "LQ4XU8RX2ULPmPq9FcUHdVmPVchP9nwXdn";
241 page.evaluate(function() {
242 $(".phrase").val("abandon abandon ability");
243 $(".phrase").trigger("input");
244 $(".network option[selected]").removeAttr("selected");
245 $(".network option[value=2]").prop("selected", true);
246 $(".network").trigger("change");
247 });
248 // check the address is generated correctly
249 waitForGenerate(function() {
250 var actual = page.evaluate(function() {
251 return $(".address:first").text();
252 });
253 if (actual != expected) {
254 console.log("Litecoin address is incorrect");
255 console.log("Expected: " + expected);
256 console.log("Actual: " + actual);
257 fail();
258 }
259 next();
260 });
261 });
262 },
263
264 // Network can be set to dogecoin
265 function() {
266 page.open(url, function(status) {
267 // set the phrase and coin
268 var expected = "DPQH2AtuzkVSG6ovjKk4jbUmZ6iXLpgbJA";
269 page.evaluate(function() {
270 $(".phrase").val("abandon abandon ability");
271 $(".phrase").trigger("input");
272 $(".network option[selected]").removeAttr("selected");
273 $(".network option[value=3]").prop("selected", true);
274 $(".network").trigger("change");
275 });
276 // check the address is generated correctly
277 waitForGenerate(function() {
278 var actual = page.evaluate(function() {
279 return $(".address:first").text();
280 });
281 if (actual != expected) {
282 console.log("Dogecoin address is incorrect");
283 console.log("Expected: " + expected);
284 console.log("Actual: " + actual);
285 fail();
286 }
287 next();
288 });
289 });
290 },
291
292 // Network can be set to shadowcash
293 function() {
294 page.open(url, function(status) {
295 // set the phrase and coin
296 var expected = "SiSZtfYAXEFvMm3XM8hmtkGDyViRwErtCG";
297 page.evaluate(function() {
298 $(".phrase").val("abandon abandon ability");
299 $(".phrase").trigger("input");
300 $(".network option[selected]").removeAttr("selected");
301 $(".network option[value=4]").prop("selected", true);
302 $(".network").trigger("change");
303 });
304 // check the address is generated correctly
305 waitForGenerate(function() {
306 var actual = page.evaluate(function() {
307 return $(".address:first").text();
308 });
309 if (actual != expected) {
310 console.log("Shadowcash address is incorrect");
311 console.log("Expected: " + expected);
312 console.log("Actual: " + actual);
313 fail();
314 }
315 next();
316 });
317 });
318 },
319
320 // Network can be set to shadowcash testnet
321 function() {
322 page.open(url, function(status) {
323 // set the phrase and coin
324 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
325 page.evaluate(function() {
326 $(".phrase").val("abandon abandon ability");
327 $(".phrase").trigger("input");
328 $(".network option[selected]").removeAttr("selected");
329 $(".network option[value=5]").prop("selected", true);
330 $(".network").trigger("change");
331 });
332 // check the address is generated correctly
333 waitForGenerate(function() {
334 var actual = page.evaluate(function() {
335 return $(".address:first").text();
336 });
337 if (actual != expected) {
338 console.log("Shadowcash testnet address is incorrect");
339 console.log("Expected: " + expected);
340 console.log("Actual: " + actual);
341 fail();
342 }
343 next();
344 });
345 });
346 },
347
348 // Network can be set to viacoin
349 function() {
350 page.open(url, function(status) {
351 // set the phrase and coin
352 var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
353 page.evaluate(function() {
354 $(".phrase").val("abandon abandon ability");
355 $(".phrase").trigger("input");
356 $(".network option[selected]").removeAttr("selected");
357 $(".network option[value=6]").prop("selected", true);
358 $(".network").trigger("change");
359 });
360 // check the address is generated correctly
361 waitForGenerate(function() {
362 var actual = page.evaluate(function() {
363 return $(".address:first").text();
364 });
365 if (actual != expected) {
366 console.log("Viacoin address is incorrect");
367 console.log("Expected: " + expected);
368 console.log("Actual: " + actual);
369 fail();
370 }
371 next();
372 });
373 });
374 },
375
376 // Network can be set to viacoin testnet
377 function() {
378 page.open(url, function(status) {
379 // set the phrase and coin
380 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
381 page.evaluate(function() {
382 $(".phrase").val("abandon abandon ability");
383 $(".phrase").trigger("input");
384 $(".network option[selected]").removeAttr("selected");
385 $(".network option[value=7]").prop("selected", true);
386 $(".network").trigger("change");
387 });
388 // check the address is generated correctly
389 waitForGenerate(function() {
390 var actual = page.evaluate(function() {
391 return $(".address:first").text();
392 });
393 if (actual != expected) {
394 console.log("Viacoin testnet address is incorrect");
395 console.log("Expected: " + expected);
396 console.log("Actual: " + actual);
397 fail();
398 }
399 next();
400 });
401 });
402 },
403
404 // Network can be set to jumbucks
405 function() {
406 page.open(url, function(status) {
407 // set the phrase and coin
408 var expected = "JLEXccwDXADK4RxBPkRez7mqsHVoJBEUew";
409 page.evaluate(function() {
410 $(".phrase").val("abandon abandon ability");
411 $(".phrase").trigger("input");
412 $(".network option[selected]").removeAttr("selected");
413 $(".network option[value=8]").prop("selected", true);
414 $(".network").trigger("change");
415 });
416 // check the address is generated correctly
417 waitForGenerate(function() {
418 var actual = page.evaluate(function() {
419 return $(".address:first").text();
420 });
421 if (actual != expected) {
422 console.log("Jumbucks address is incorrect");
423 console.log("Expected: " + expected);
424 console.log("Actual: " + actual);
425 fail();
426 }
427 next();
428 });
429 });
430 },
431
432 // Network can be set to clam
433 function() {
434 page.open(url, function(status) {
435 // set the phrase and coin
436 var expected = "xCp4sakjVx4pUAZ6cBCtuin8Ddb6U1sk9y";
437 page.evaluate(function() {
438 $(".phrase").val("abandon abandon ability");
439 $(".phrase").trigger("input");
440 $(".network option[selected]").removeAttr("selected");
441 $(".network option[value=9]").prop("selected", true);
442 $(".network").trigger("change");
443 });
444 // check the address is generated correctly
445 waitForGenerate(function() {
446 var actual = page.evaluate(function() {
447 return $(".address:first").text();
448 });
449 if (actual != expected) {
450 console.log("CLAM address is incorrect");
451 console.log("Expected: " + expected);
452 console.log("Actual: " + actual);
453 fail();
454 }
455 next();
456 });
457 });
458 },
459
460 // Network can be set to dash
461 function() {
462 page.open(url, function(status) {
463 // set the phrase and coin
464 var expected = "XdbhtMuGsPSkE6bPdNTHoFSszQKmK4S5LT";
465 page.evaluate(function() {
466 $(".phrase").val("abandon abandon ability");
467 $(".phrase").trigger("input");
468 $(".network option[selected]").removeAttr("selected");
469 $(".network option[value=10]").prop("selected", true);
470 $(".network").trigger("change");
471 });
472 // check the address is generated correctly
473 waitForGenerate(function() {
474 var actual = page.evaluate(function() {
475 return $(".address:first").text();
476 });
477 if (actual != expected) {
478 console.log("DASH address is incorrect");
479 console.log("Expected: " + expected);
480 console.log("Actual: " + actual);
481 fail();
482 }
483 next();
484 });
485 });
486 },
487
488 // Network can be set to namecoin
489 function() {
490 page.open(url, function(status) {
491 // set the phrase and coin
492 var expected = "Mw2vK2Bvex1yYtYF6sfbEg2YGoUc98YUD2";
493 page.evaluate(function() {
494 $(".phrase").val("abandon abandon ability");
495 $(".phrase").trigger("input");
496 $(".network option[selected]").removeAttr("selected");
497 $(".network option[value=11]").prop("selected", true);
498 $(".network").trigger("change");
499 });
500 // check the address is generated correctly
501 waitForGenerate(function() {
502 var actual = page.evaluate(function() {
503 return $(".address:first").text();
504 });
505 if (actual != expected) {
506 console.log("Namecoin address is incorrect");
507 console.log("Expected: " + expected);
508 console.log("Actual: " + actual);
509 fail();
510 }
511 next();
512 });
513 });
514 },
515
516 // Network can be set to peercoin
517 function() {
518 page.open(url, function(status) {
519 // set the phrase and coin
520 var expected = "PVAiioTaK2eDHSEo3tppT9AVdBYqxRTBAm";
521 page.evaluate(function() {
522 $(".phrase").val("abandon abandon ability");
523 $(".phrase").trigger("input");
524 $(".network option[selected]").removeAttr("selected");
525 $(".network option[value=12]").prop("selected", true);
526 $(".network").trigger("change");
527 });
528 // check the address is generated correctly
529 waitForGenerate(function() {
530 var actual = page.evaluate(function() {
531 return $(".address:first").text();
532 });
533 if (actual != expected) {
534 console.log("Peercoin address is incorrect");
535 console.log("Expected: " + expected);
536 console.log("Actual: " + actual);
537 fail();
538 }
539 next();
540 });
541 });
542 },
543
544 // BIP39 seed is set from phrase
545 function() {
546 page.open(url, function(status) {
547 // set the phrase
548 var expected = "20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3";
549 page.evaluate(function() {
550 $(".phrase").val("abandon abandon ability");
551 $(".phrase").trigger("input");
552 });
553 // check the address is generated correctly
554 waitForGenerate(function() {
555 var actual = page.evaluate(function() {
556 return $(".seed").val();
557 });
558 if (actual != expected) {
559 console.log("BIP39 seed is incorrectly generated from mnemonic");
560 console.log("Expected: " + expected);
561 console.log("Actual: " + actual);
562 fail();
563 }
564 next();
565 });
566 });
567 },
568
569 // BIP32 root key is set from phrase
570 function() {
571 page.open(url, function(status) {
572 // set the phrase
573 var expected = "xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi";
574 page.evaluate(function() {
575 $(".phrase").val("abandon abandon ability");
576 $(".phrase").trigger("input");
577 });
578 // check the address is generated correctly
579 waitForGenerate(function() {
580 var actual = page.evaluate(function() {
581 return $(".root-key").val();
582 });
583 if (actual != expected) {
584 console.log("Root key is incorrectly generated from mnemonic");
585 console.log("Expected: " + expected);
586 console.log("Actual: " + actual);
587 fail();
588 }
589 next();
590 });
591 });
592 },
593
594 // Tabs show correct addresses when changed
595 function() {
596 page.open(url, function(status) {
597 // set the phrase
598 var expected = "17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz";
599 page.evaluate(function() {
600 $(".phrase").val("abandon abandon ability");
601 $(".phrase").trigger("input");
602 });
603 // change tabs
604 waitForGenerate(function() {
605 page.evaluate(function() {
606 $("#bip32-tab a").click();
607 });
608 // check the address is generated correctly
609 waitForGenerate(function() {
610 var actual = page.evaluate(function() {
611 return $(".address:first").text();
612 });
613 if (actual != expected) {
614 console.log("Clicking tab generates incorrect address");
615 console.log("Expected: " + expected);
616 console.log("Actual: " + actual);
617 fail();
618 }
619 next();
620 });
621 });
622 });
623 },
624
625 // BIP44 derivation path is shown
626 function() {
627 page.open(url, function(status) {
628 // set the phrase
629 var expected = "m/44'/0'/0'/0";
630 page.evaluate(function() {
631 $(".phrase").val("abandon abandon ability");
632 $(".phrase").trigger("input");
633 });
634 // check the derivation path of the first address
635 waitForGenerate(function() {
636 var actual = page.evaluate(function() {
637 return $("#bip44 .path").val();
638 });
639 if (actual != expected) {
640 console.log("BIP44 derivation path is incorrect");
641 console.log("Expected: " + expected);
642 console.log("Actual: " + actual);
643 fail();
644 }
645 next();
646 });
647 });
648 },
649
650 // BIP44 extended private key is shown
651 function() {
652 page.open(url, function(status) {
653 // set the phrase
654 var expected = "xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG";
655 page.evaluate(function() {
656 $(".phrase").val("abandon abandon ability");
657 $(".phrase").trigger("input");
658 });
659 // check the BIP44 extended private key
660 waitForGenerate(function() {
661 var actual = page.evaluate(function() {
662 return $(".extended-priv-key").val();
663 });
664 if (actual != expected) {
665 console.log("BIP44 extended private key is incorrect");
666 console.log("Expected: " + expected);
667 console.log("Actual: " + actual);
668 fail();
669 }
670 next();
671 });
672 });
673 },
674
675 // BIP44 extended public key is shown
676 function() {
677 page.open(url, function(status) {
678 // set the phrase
679 var expected = "xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM";
680 page.evaluate(function() {
681 $(".phrase").val("abandon abandon ability");
682 $(".phrase").trigger("input");
683 });
684 // check the BIP44 extended public key
685 waitForGenerate(function() {
686 var actual = page.evaluate(function() {
687 return $(".extended-pub-key").val();
688 });
689 if (actual != expected) {
690 console.log("BIP44 extended public key is incorrect");
691 console.log("Expected: " + expected);
692 console.log("Actual: " + actual);
693 fail();
694 }
695 next();
696 });
697 });
698 },
699
700 // BIP44 purpose field changes address list
701 function() {
702 page.open(url, function(status) {
703 // set the phrase
704 var expected = "1JbDzRJ2cDT8aat2xwKd6Pb2zzavow5MhF";
705 page.evaluate(function() {
706 $(".phrase").val("abandon abandon ability");
707 $(".phrase").trigger("input");
708 });
709 waitForGenerate(function() {
710 // change the bip44 purpose field to 45
711 page.evaluate(function() {
712 $("#bip44 .purpose").val("45");
713 $("#bip44 .purpose").trigger("input");
714 });
715 waitForGenerate(function() {
716 // check the address for the new derivation path
717 var actual = page.evaluate(function() {
718 return $(".address:first").text();
719 });
720 if (actual != expected) {
721 console.log("BIP44 purpose field generates incorrect address");
722 console.log("Expected: " + expected);
723 console.log("Actual: " + actual);
724 fail();
725 }
726 next();
727 });
728 });
729 });
730 },
731
732 // BIP44 coin field changes address list
733 function() {
734 page.open(url, function(status) {
735 // set the phrase
736 var expected = "1F6dB2djQYrxoyfZZmfr6D5voH8GkJTghk";
737 page.evaluate(function() {
738 $(".phrase").val("abandon abandon ability");
739 $(".phrase").trigger("input");
740 });
741 waitForGenerate(function() {
742 // change the bip44 purpose field to 45
743 page.evaluate(function() {
744 $("#bip44 .coin").val("1");
745 $("#bip44 .coin").trigger("input");
746 });
747 waitForGenerate(function() {
748 // check the address for the new derivation path
749 var actual = page.evaluate(function() {
750 return $(".address:first").text();
751 });
752 if (actual != expected) {
753 console.log("BIP44 coin field generates incorrect address");
754 console.log("Expected: " + expected);
755 console.log("Actual: " + actual);
756 fail();
757 }
758 next();
759 });
760 });
761 });
762 },
763
764 // BIP44 account field changes address list
765 function() {
766 page.open(url, function(status) {
767 // set the phrase
768 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
769 page.evaluate(function() {
770 $(".phrase").val("abandon abandon ability");
771 $(".phrase").trigger("input");
772 });
773 waitForGenerate(function() {
774 // change the bip44 purpose field to 45
775 page.evaluate(function() {
776 $("#bip44 .account").val("1");
777 $("#bip44 .account").trigger("input");
778 });
779 waitForGenerate(function() {
780 // check the address for the new derivation path
781 var actual = page.evaluate(function() {
782 return $(".address:first").text();
783 });
784 if (actual != expected) {
785 console.log("BIP44 account field generates incorrect address");
786 console.log("Expected: " + expected);
787 console.log("Actual: " + actual);
788 fail();
789 }
790 next();
791 });
792 });
793 });
794 },
795
796 // BIP44 change field changes address list
797 function() {
798 page.open(url, function(status) {
799 // set the phrase
800 var expected = "1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo";
801 page.evaluate(function() {
802 $(".phrase").val("abandon abandon ability");
803 $(".phrase").trigger("input");
804 });
805 waitForGenerate(function() {
806 // change the bip44 purpose field to 45
807 page.evaluate(function() {
808 $("#bip44 .change").val("1");
809 $("#bip44 .change").trigger("input");
810 });
811 waitForGenerate(function() {
812 // check the address for the new derivation path
813 var actual = page.evaluate(function() {
814 return $(".address:first").text();
815 });
816 if (actual != expected) {
817 console.log("BIP44 change field generates incorrect address");
818 console.log("Expected: " + expected);
819 console.log("Actual: " + actual);
820 fail();
821 }
822 next();
823 });
824 });
825 });
826 },
827
828 // BIP32 derivation path can be set
829 function() {
830 page.open(url, function(status) {
831 // set the phrase
832 var expected = "16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L";
833 page.evaluate(function() {
834 $(".phrase").val("abandon abandon ability");
835 $(".phrase").trigger("input");
836 });
837 // change tabs
838 waitForGenerate(function() {
839 page.evaluate(function() {
840 $("#bip32-tab a").click();
841 });
842 // set the derivation path to m/1
843 waitForGenerate(function() {
844 page.evaluate(function() {
845 $("#bip32 .path").val("m/1");
846 $("#bip32 .path").trigger("input");
847 });
848 // check the address is generated correctly
849 waitForGenerate(function() {
850 var actual = page.evaluate(function() {
851 return $(".address:first").text();
852 });
853 if (actual != expected) {
854 console.log("Custom BIP32 path generates incorrect address");
855 console.log("Expected: " + expected);
856 console.log("Actual: " + actual);
857 fail();
858 }
859 next();
860 });
861 });
862 });
863 });
864 },
865
866 // BIP32 can use hardened derivation paths
867 function() {
868 page.open(url, function(status) {
869 // set the phrase
870 var expected = "14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4";
871 page.evaluate(function() {
872 $(".phrase").val("abandon abandon ability");
873 $(".phrase").trigger("input");
874 });
875 // change tabs
876 waitForGenerate(function() {
877 page.evaluate(function() {
878 $("#bip32-tab a").click();
879 });
880 // set the derivation path to m/0'
881 waitForGenerate(function() {
882 page.evaluate(function() {
883 $("#bip32 .path").val("m/0'");
884 $("#bip32 .path").trigger("input");
885 });
886 // check the address is generated correctly
887 waitForGenerate(function() {
888 var actual = page.evaluate(function() {
889 return $(".address:first").text();
890 });
891 if (actual != expected) {
892 console.log("Hardened BIP32 path generates incorrect address");
893 console.log("Expected: " + expected);
894 console.log("Actual: " + actual);
895 fail();
896 }
897 next();
898 });
899 });
900 });
901 });
902 },
903
904 // BIP32 extended private key is shown
905 function() {
906 page.open(url, function(status) {
907 // set the phrase
908 var expected = "xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe";
909 page.evaluate(function() {
910 $(".phrase").val("abandon abandon ability");
911 $(".phrase").trigger("input");
912 });
913 // change tabs
914 waitForGenerate(function() {
915 page.evaluate(function() {
916 $("#bip32-tab a").click();
917 });
918 // check the extended private key is generated correctly
919 waitForGenerate(function() {
920 var actual = page.evaluate(function() {
921 return $(".extended-priv-key").val();
922 });
923 if (actual != expected) {
924 console.log("BIP32 extended private key is incorrect");
925 console.log("Expected: " + expected);
926 console.log("Actual: " + actual);
927 fail();
928 }
929 next();
930 });
931 });
932 });
933 },
934
935 // BIP32 extended public key is shown
936 function() {
937 page.open(url, function(status) {
938 // set the phrase
939 var expected = "xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P";
940 page.evaluate(function() {
941 $(".phrase").val("abandon abandon ability");
942 $(".phrase").trigger("input");
943 });
944 // change tabs
945 waitForGenerate(function() {
946 page.evaluate(function() {
947 $("#bip32-tab a").click();
948 });
949 // check the extended public key is generated correctly
950 waitForGenerate(function() {
951 var actual = page.evaluate(function() {
952 return $(".extended-pub-key").val();
953 });
954 if (actual != expected) {
955 console.log("BIP32 extended public key is incorrect");
956 console.log("Expected: " + expected);
957 console.log("Actual: " + actual);
958 fail();
959 }
960 next();
961 });
962 });
963 });
964 },
965
966 // Derivation path is shown in table
967 function() {
968 page.open(url, function(status) {
969 // set the phrase
970 var expected = "m/44'/0'/0'/0/0";
971 page.evaluate(function() {
972 $(".phrase").val("abandon abandon ability");
973 $(".phrase").trigger("input");
974 });
975 // check for derivation path in table
976 waitForGenerate(function() {
977 var actual = page.evaluate(function() {
978 return $(".index:first").text();
979 });
980 if (actual != expected) {
981 console.log("Derivation path shown incorrectly in table");
982 console.log("Expected: " + expected);
983 console.log("Actual: " + actual);
984 fail();
985 }
986 next();
987 });
988 });
989 },
990
991 // Derivation path for address can be hardened
992 function() {
993 page.open(url, function(status) {
994 // set the phrase
995 var expected = "18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd";
996 page.evaluate(function() {
997 $(".phrase").val("abandon abandon ability");
998 $(".phrase").trigger("input");
999 });
1000 // change tabs
1001 waitForGenerate(function() {
1002 page.evaluate(function() {
1003 $("#bip32-tab a").click();
1004 });
1005 waitForGenerate(function() {
1006 // select the hardened addresses option
1007 page.evaluate(function() {
1008 $(".hardened-addresses").prop("checked", true);
1009 $(".hardened-addresses").trigger("change");
1010 });
1011 waitForGenerate(function() {
1012 // check the generated address is hardened
1013 var actual = page.evaluate(function() {
1014 return $(".address:first").text();
1015 });
1016 if (actual != expected) {
1017 console.log("Hardened address is incorrect");
1018 console.log("Expected: " + expected);
1019 console.log("Actual: " + actual);
1020 fail();
1021 }
1022 next();
1023 });
1024 });
1025 });
1026 });
1027 },
1028
1029 // Derivation path visibility can be toggled
1030 function() {
1031 page.open(url, function(status) {
1032 // set the phrase
1033 page.evaluate(function() {
1034 $(".phrase").val("abandon abandon ability");
1035 $(".phrase").trigger("input");
1036 });
1037 waitForGenerate(function() {
1038 // toggle path visibility
1039 page.evaluate(function() {
1040 $(".index-toggle").click();
1041 });
1042 // check the path is not visible
1043 var isInvisible = page.evaluate(function() {
1044 return $(".index:first span").hasClass("invisible");
1045 });
1046 if (!isInvisible) {
1047 console.log("Toggled derivation path is visible");
1048 fail();
1049 }
1050 next();
1051 });
1052 });
1053 },
1054
1055 // Address is shown
1056 function() {
1057 page.open(url, function(status) {
1058 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1059 // set the phrase
1060 page.evaluate(function() {
1061 $(".phrase").val("abandon abandon ability").trigger("input");
1062 });
1063 // get the address
1064 waitForGenerate(function() {
1065 var actual = page.evaluate(function() {
1066 return $(".address:first").text();
1067 });
1068 if (actual != expected) {
1069 console.log("Address is not shown");
1070 console.log("Expected: " + expected);
1071 console.log("Got: " + actual);
1072 fail();
1073 }
1074 next();
1075 });
1076 });
1077 },
1078
1079 // Addresses are shown in order of derivation path
1080 function() {
1081 page.open(url, function(status) {
1082 // set the phrase
1083 page.evaluate(function() {
1084 $(".phrase").val("abandon abandon ability").trigger("input");
1085 });
1086 // get the derivation paths
1087 waitForGenerate(function() {
1088 var paths = page.evaluate(function() {
1089 return $(".index").map(function(i, e) {
1090 return $(e).text();
1091 });
1092 });
1093 if (paths.length != 20) {
1094 console.log("Total paths is less than expected: " + paths.length);
1095 fail();
1096 }
1097 for (var i=0; i<paths.length; i++) {
1098 var expected = "m/44'/0'/0'/0/" + i;
1099 var actual = paths[i];
1100 if (actual != expected) {
1101 console.log("Path " + i + " is incorrect");
1102 console.log("Expected: " + expected);
1103 console.log("Actual: " + actual);
1104 fail();
1105 }
1106 }
1107 next();
1108 });
1109 });
1110 },
1111
1112 // Address visibility can be toggled
1113 function() {
1114 page.open(url, function(status) {
1115 // set the phrase
1116 page.evaluate(function() {
1117 $(".phrase").val("abandon abandon ability");
1118 $(".phrase").trigger("input");
1119 });
1120 waitForGenerate(function() {
1121 // toggle address visibility
1122 page.evaluate(function() {
1123 $(".address-toggle").click();
1124 });
1125 // check the address is not visible
1126 var isInvisible = page.evaluate(function() {
1127 return $(".address:first span").hasClass("invisible");
1128 });
1129 if (!isInvisible) {
1130 console.log("Toggled address is visible");
1131 fail();
1132 }
1133 next();
1134 });
1135 });
1136 },
1137
1138 // Private key is shown
1139 function() {
1140 page.open(url, function(status) {
1141 var expected = "L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE";
1142 // set the phrase
1143 page.evaluate(function() {
1144 $(".phrase").val("abandon abandon ability").trigger("input");
1145 });
1146 // get the address
1147 waitForGenerate(function() {
1148 var actual = page.evaluate(function() {
1149 return $(".privkey:first").text();
1150 });
1151 if (actual != expected) {
1152 console.log("Private key is not shown");
1153 console.log("Expected: " + expected);
1154 console.log("Got: " + actual);
1155 fail();
1156 }
1157 next();
1158 });
1159 });
1160 },
1161
1162 // Private key visibility can be toggled
1163 function() {
1164 page.open(url, function(status) {
1165 // set the phrase
1166 page.evaluate(function() {
1167 $(".phrase").val("abandon abandon ability");
1168 $(".phrase").trigger("input");
1169 });
1170 waitForGenerate(function() {
1171 // toggle private key visibility
1172 page.evaluate(function() {
1173 $(".private-key-toggle").click();
1174 });
1175 // check the private key is not visible
1176 var isInvisible = page.evaluate(function() {
1177 return $(".privkey:first span").hasClass("invisible");
1178 });
1179 if (!isInvisible) {
1180 console.log("Toggled private key is visible");
1181 fail();
1182 }
1183 next();
1184 });
1185 });
1186 },
1187
1188 // More addresses can be generated
1189 function() {
1190 page.open(url, function(status) {
1191 // set the phrase
1192 page.evaluate(function() {
1193 $(".phrase").val("abandon abandon ability");
1194 $(".phrase").trigger("input");
1195 });
1196 waitForGenerate(function() {
1197 // generate more addresses
1198 page.evaluate(function() {
1199 $(".more").click();
1200 });
1201 waitForGenerate(function() {
1202 // check there are more addresses
1203 var addressCount = page.evaluate(function() {
1204 return $(".address").length;
1205 });
1206 if (addressCount != 40) {
1207 console.log("More addresses cannot be generated");
1208 fail();
1209 }
1210 next();
1211 });
1212 });
1213 });
1214 },
1215
1216 // A custom number of additional addresses can be generated
1217 function() {
1218 page.open(url, function(status) {
1219 // set the phrase
1220 page.evaluate(function() {
1221 $(".phrase").val("abandon abandon ability");
1222 $(".phrase").trigger("input");
1223 });
1224 waitForGenerate(function() {
1225 // get the current number of addresses
1226 var oldAddressCount = page.evaluate(function() {
1227 return $(".address").length;
1228 });
1229 // set a custom number of additional addresses
1230 page.evaluate(function() {
1231 $(".rows-to-add").val(1);
1232 });
1233 // generate more addresses
1234 page.evaluate(function() {
1235 $(".more").click();
1236 });
1237 waitForGenerate(function() {
1238 // check there are the correct number of addresses
1239 var newAddressCount = page.evaluate(function() {
1240 return $(".address").length;
1241 });
1242 if (newAddressCount - oldAddressCount != 1) {
1243 console.log("Number of additional addresses cannot be customized");
1244 console.log(newAddressCount)
1245 console.log(oldAddressCount)
1246 fail();
1247 }
1248 next();
1249 });
1250 });
1251 });
1252 },
1253
1254 // Additional addresses are shown in order of derivation path
1255 function() {
1256 page.open(url, function(status) {
1257 // set the phrase
1258 page.evaluate(function() {
1259 $(".phrase").val("abandon abandon ability").trigger("input");
1260 });
1261 waitForGenerate(function() {
1262 // generate more addresses
1263 page.evaluate(function() {
1264 $(".more").click();
1265 });
1266 // get the derivation paths
1267 waitForGenerate(function() {
1268 var paths = page.evaluate(function() {
1269 return $(".index").map(function(i, e) {
1270 return $(e).text();
1271 });
1272 });
1273 if (paths.length != 40) {
1274 console.log("Total additional paths is less than expected: " + paths.length);
1275 fail();
1276 }
1277 for (var i=0; i<paths.length; i++) {
1278 var expected = "m/44'/0'/0'/0/" + i;
1279 var actual = paths[i];
1280 if (actual != expected) {
1281 console.log("Path " + i + " is not in correct order");
1282 console.log("Expected: " + expected);
1283 console.log("Actual: " + actual);
1284 fail();
1285 }
1286 }
1287 next();
1288 });
1289 });
1290 });
1291 },
1292
1293 // BIP32 root key can be set by the user
1294 // Setting BIP32 root key clears the existing phrase, passphrase and seed
1295 // Clearing of phrase, passphrase and seed can be cancelled by user
1296 // Custom BIP32 root key is used when changing the derivation path
1297
1298 // Incorrect mnemonic shows error
1299 // Incorrect word shows suggested replacement
1300 // Incorrect BIP32 root key shows error
1301 // Derivation path not starting with m shows error
1302 // Derivation path containing invalid characters shows useful error
1303
1304 // Github Issue 11: Default word length is 15
1305 // https://github.com/dcpos/bip39/issues/11
1306
1307 // Github Issue 12: Generate more rows with private keys hidden
1308 // https://github.com/dcpos/bip39/issues/12
1309
1310 // Github Issue 19: Mnemonic is not sensitive to whitespace
1311 // https://github.com/dcpos/bip39/issues/19
1312
1313 // Github Issue 23: Use correct derivation path when changing tabs
1314 // https://github.com/dcpos/bip39/issues/23
1315
1316 // Github Issue 26: When using a Root key derrived altcoins are incorrect
1317 // https://github.com/dcpos/bip39/issues/26
1318
1319 ];
1320
1321 console.log("Running tests...");
1322 tests = shuffle(tests);
1323 next();