]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blob - tests.js
Test toggling address visibility
[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 // BIP39 seed is set from phrase
489 function() {
490 page.open(url, function(status) {
491 // set the phrase
492 var expected = "20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3";
493 page.evaluate(function() {
494 $(".phrase").val("abandon abandon ability");
495 $(".phrase").trigger("input");
496 });
497 // check the address is generated correctly
498 waitForGenerate(function() {
499 var actual = page.evaluate(function() {
500 return $(".seed").val();
501 });
502 if (actual != expected) {
503 console.log("BIP39 seed is incorrectly generated from mnemonic");
504 console.log("Expected: " + expected);
505 console.log("Actual: " + actual);
506 fail();
507 }
508 next();
509 });
510 });
511 },
512
513 // BIP32 root key is set from phrase
514 function() {
515 page.open(url, function(status) {
516 // set the phrase
517 var expected = "xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi";
518 page.evaluate(function() {
519 $(".phrase").val("abandon abandon ability");
520 $(".phrase").trigger("input");
521 });
522 // check the address is generated correctly
523 waitForGenerate(function() {
524 var actual = page.evaluate(function() {
525 return $(".root-key").val();
526 });
527 if (actual != expected) {
528 console.log("Root key is incorrectly generated from mnemonic");
529 console.log("Expected: " + expected);
530 console.log("Actual: " + actual);
531 fail();
532 }
533 next();
534 });
535 });
536 },
537
538 // Tabs show correct addresses when changed
539 function() {
540 page.open(url, function(status) {
541 // set the phrase
542 var expected = "17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz";
543 page.evaluate(function() {
544 $(".phrase").val("abandon abandon ability");
545 $(".phrase").trigger("input");
546 });
547 // change tabs
548 waitForGenerate(function() {
549 page.evaluate(function() {
550 $("#bip32-tab a").click();
551 });
552 // check the address is generated correctly
553 waitForGenerate(function() {
554 var actual = page.evaluate(function() {
555 return $(".address:first").text();
556 });
557 if (actual != expected) {
558 console.log("Clicking tab generates incorrect address");
559 console.log("Expected: " + expected);
560 console.log("Actual: " + actual);
561 fail();
562 }
563 next();
564 });
565 });
566 });
567 },
568
569 // BIP44 derivation path is shown
570 function() {
571 page.open(url, function(status) {
572 // set the phrase
573 var expected = "m/44'/0'/0'/0";
574 page.evaluate(function() {
575 $(".phrase").val("abandon abandon ability");
576 $(".phrase").trigger("input");
577 });
578 // check the derivation path of the first address
579 waitForGenerate(function() {
580 var actual = page.evaluate(function() {
581 return $("#bip44 .path").val();
582 });
583 if (actual != expected) {
584 console.log("BIP44 derivation path is incorrect");
585 console.log("Expected: " + expected);
586 console.log("Actual: " + actual);
587 fail();
588 }
589 next();
590 });
591 });
592 },
593
594 // BIP44 extended private key is shown
595 function() {
596 page.open(url, function(status) {
597 // set the phrase
598 var expected = "xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG";
599 page.evaluate(function() {
600 $(".phrase").val("abandon abandon ability");
601 $(".phrase").trigger("input");
602 });
603 // check the BIP44 extended private key
604 waitForGenerate(function() {
605 var actual = page.evaluate(function() {
606 return $(".extended-priv-key").val();
607 });
608 if (actual != expected) {
609 console.log("BIP44 extended private key is incorrect");
610 console.log("Expected: " + expected);
611 console.log("Actual: " + actual);
612 fail();
613 }
614 next();
615 });
616 });
617 },
618
619 // BIP44 extended public key is shown
620 function() {
621 page.open(url, function(status) {
622 // set the phrase
623 var expected = "xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM";
624 page.evaluate(function() {
625 $(".phrase").val("abandon abandon ability");
626 $(".phrase").trigger("input");
627 });
628 // check the BIP44 extended public key
629 waitForGenerate(function() {
630 var actual = page.evaluate(function() {
631 return $(".extended-pub-key").val();
632 });
633 if (actual != expected) {
634 console.log("BIP44 extended public key is incorrect");
635 console.log("Expected: " + expected);
636 console.log("Actual: " + actual);
637 fail();
638 }
639 next();
640 });
641 });
642 },
643
644 // BIP44 purpose field changes address list
645 function() {
646 page.open(url, function(status) {
647 // set the phrase
648 var expected = "1JbDzRJ2cDT8aat2xwKd6Pb2zzavow5MhF";
649 page.evaluate(function() {
650 $(".phrase").val("abandon abandon ability");
651 $(".phrase").trigger("input");
652 });
653 waitForGenerate(function() {
654 // change the bip44 purpose field to 45
655 page.evaluate(function() {
656 $("#bip44 .purpose").val("45");
657 $("#bip44 .purpose").trigger("input");
658 });
659 waitForGenerate(function() {
660 // check the address for the new derivation path
661 var actual = page.evaluate(function() {
662 return $(".address:first").text();
663 });
664 if (actual != expected) {
665 console.log("BIP44 purpose field generates incorrect address");
666 console.log("Expected: " + expected);
667 console.log("Actual: " + actual);
668 fail();
669 }
670 next();
671 });
672 });
673 });
674 },
675
676 // BIP44 coin field changes address list
677 function() {
678 page.open(url, function(status) {
679 // set the phrase
680 var expected = "1F6dB2djQYrxoyfZZmfr6D5voH8GkJTghk";
681 page.evaluate(function() {
682 $(".phrase").val("abandon abandon ability");
683 $(".phrase").trigger("input");
684 });
685 waitForGenerate(function() {
686 // change the bip44 purpose field to 45
687 page.evaluate(function() {
688 $("#bip44 .coin").val("1");
689 $("#bip44 .coin").trigger("input");
690 });
691 waitForGenerate(function() {
692 // check the address for the new derivation path
693 var actual = page.evaluate(function() {
694 return $(".address:first").text();
695 });
696 if (actual != expected) {
697 console.log("BIP44 coin field generates incorrect address");
698 console.log("Expected: " + expected);
699 console.log("Actual: " + actual);
700 fail();
701 }
702 next();
703 });
704 });
705 });
706 },
707
708 // BIP44 account field changes address list
709 function() {
710 page.open(url, function(status) {
711 // set the phrase
712 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
713 page.evaluate(function() {
714 $(".phrase").val("abandon abandon ability");
715 $(".phrase").trigger("input");
716 });
717 waitForGenerate(function() {
718 // change the bip44 purpose field to 45
719 page.evaluate(function() {
720 $("#bip44 .account").val("1");
721 $("#bip44 .account").trigger("input");
722 });
723 waitForGenerate(function() {
724 // check the address for the new derivation path
725 var actual = page.evaluate(function() {
726 return $(".address:first").text();
727 });
728 if (actual != expected) {
729 console.log("BIP44 account field generates incorrect address");
730 console.log("Expected: " + expected);
731 console.log("Actual: " + actual);
732 fail();
733 }
734 next();
735 });
736 });
737 });
738 },
739
740 // BIP44 change field changes address list
741 function() {
742 page.open(url, function(status) {
743 // set the phrase
744 var expected = "1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo";
745 page.evaluate(function() {
746 $(".phrase").val("abandon abandon ability");
747 $(".phrase").trigger("input");
748 });
749 waitForGenerate(function() {
750 // change the bip44 purpose field to 45
751 page.evaluate(function() {
752 $("#bip44 .change").val("1");
753 $("#bip44 .change").trigger("input");
754 });
755 waitForGenerate(function() {
756 // check the address for the new derivation path
757 var actual = page.evaluate(function() {
758 return $(".address:first").text();
759 });
760 if (actual != expected) {
761 console.log("BIP44 change field generates incorrect address");
762 console.log("Expected: " + expected);
763 console.log("Actual: " + actual);
764 fail();
765 }
766 next();
767 });
768 });
769 });
770 },
771
772 // BIP32 derivation path can be set
773 function() {
774 page.open(url, function(status) {
775 // set the phrase
776 var expected = "16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L";
777 page.evaluate(function() {
778 $(".phrase").val("abandon abandon ability");
779 $(".phrase").trigger("input");
780 });
781 // change tabs
782 waitForGenerate(function() {
783 page.evaluate(function() {
784 $("#bip32-tab a").click();
785 });
786 // set the derivation path to m/1
787 waitForGenerate(function() {
788 page.evaluate(function() {
789 $("#bip32 .path").val("m/1");
790 $("#bip32 .path").trigger("input");
791 });
792 // check the address is generated correctly
793 waitForGenerate(function() {
794 var actual = page.evaluate(function() {
795 return $(".address:first").text();
796 });
797 if (actual != expected) {
798 console.log("Custom BIP32 path generates incorrect address");
799 console.log("Expected: " + expected);
800 console.log("Actual: " + actual);
801 fail();
802 }
803 next();
804 });
805 });
806 });
807 });
808 },
809
810 // BIP32 can use hardened derivation paths
811 function() {
812 page.open(url, function(status) {
813 // set the phrase
814 var expected = "14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4";
815 page.evaluate(function() {
816 $(".phrase").val("abandon abandon ability");
817 $(".phrase").trigger("input");
818 });
819 // change tabs
820 waitForGenerate(function() {
821 page.evaluate(function() {
822 $("#bip32-tab a").click();
823 });
824 // set the derivation path to m/0'
825 waitForGenerate(function() {
826 page.evaluate(function() {
827 $("#bip32 .path").val("m/0'");
828 $("#bip32 .path").trigger("input");
829 });
830 // check the address is generated correctly
831 waitForGenerate(function() {
832 var actual = page.evaluate(function() {
833 return $(".address:first").text();
834 });
835 if (actual != expected) {
836 console.log("Hardened BIP32 path generates incorrect address");
837 console.log("Expected: " + expected);
838 console.log("Actual: " + actual);
839 fail();
840 }
841 next();
842 });
843 });
844 });
845 });
846 },
847
848 // BIP32 extended private key is shown
849 function() {
850 page.open(url, function(status) {
851 // set the phrase
852 var expected = "xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe";
853 page.evaluate(function() {
854 $(".phrase").val("abandon abandon ability");
855 $(".phrase").trigger("input");
856 });
857 // change tabs
858 waitForGenerate(function() {
859 page.evaluate(function() {
860 $("#bip32-tab a").click();
861 });
862 // check the extended private key is generated correctly
863 waitForGenerate(function() {
864 var actual = page.evaluate(function() {
865 return $(".extended-priv-key").val();
866 });
867 if (actual != expected) {
868 console.log("BIP32 extended private key is incorrect");
869 console.log("Expected: " + expected);
870 console.log("Actual: " + actual);
871 fail();
872 }
873 next();
874 });
875 });
876 });
877 },
878
879 // BIP32 extended public key is shown
880 function() {
881 page.open(url, function(status) {
882 // set the phrase
883 var expected = "xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P";
884 page.evaluate(function() {
885 $(".phrase").val("abandon abandon ability");
886 $(".phrase").trigger("input");
887 });
888 // change tabs
889 waitForGenerate(function() {
890 page.evaluate(function() {
891 $("#bip32-tab a").click();
892 });
893 // check the extended public key is generated correctly
894 waitForGenerate(function() {
895 var actual = page.evaluate(function() {
896 return $(".extended-pub-key").val();
897 });
898 if (actual != expected) {
899 console.log("BIP32 extended public key is incorrect");
900 console.log("Expected: " + expected);
901 console.log("Actual: " + actual);
902 fail();
903 }
904 next();
905 });
906 });
907 });
908 },
909
910 // Derivation path is shown in table
911 function() {
912 page.open(url, function(status) {
913 // set the phrase
914 var expected = "m/44'/0'/0'/0/0";
915 page.evaluate(function() {
916 $(".phrase").val("abandon abandon ability");
917 $(".phrase").trigger("input");
918 });
919 // check for derivation path in table
920 waitForGenerate(function() {
921 var actual = page.evaluate(function() {
922 return $(".index:first").text();
923 });
924 if (actual != expected) {
925 console.log("Derivation path shown incorrectly in table");
926 console.log("Expected: " + expected);
927 console.log("Actual: " + actual);
928 fail();
929 }
930 next();
931 });
932 });
933 },
934
935 // Derivation path for address can be hardened
936 function() {
937 page.open(url, function(status) {
938 // set the phrase
939 var expected = "18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd";
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 waitForGenerate(function() {
950 // select the hardened addresses option
951 page.evaluate(function() {
952 $(".hardened-addresses").prop("checked", true);
953 $(".hardened-addresses").trigger("change");
954 });
955 waitForGenerate(function() {
956 // check the generated address is hardened
957 var actual = page.evaluate(function() {
958 return $(".address:first").text();
959 });
960 if (actual != expected) {
961 console.log("Hardened address is incorrect");
962 console.log("Expected: " + expected);
963 console.log("Actual: " + actual);
964 fail();
965 }
966 next();
967 });
968 });
969 });
970 });
971 },
972
973 // Derivation path visibility can be toggled
974 function() {
975 page.open(url, function(status) {
976 // set the phrase
977 page.evaluate(function() {
978 $(".phrase").val("abandon abandon ability");
979 $(".phrase").trigger("input");
980 });
981 waitForGenerate(function() {
982 // toggle path visibility
983 page.evaluate(function() {
984 $(".index-toggle").click();
985 });
986 // check the path is not visible
987 var isInvisible = page.evaluate(function() {
988 return $(".index:first span").hasClass("invisible");
989 });
990 if (!isInvisible) {
991 console.log("Toggled derivation path is visible");
992 fail();
993 }
994 next();
995 });
996 });
997 },
998
999 // Address is shown
1000 function() {
1001 page.open(url, function(status) {
1002 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1003 // set the phrase
1004 page.evaluate(function() {
1005 $(".phrase").val("abandon abandon ability").trigger("input");
1006 });
1007 // get the address
1008 waitForGenerate(function() {
1009 var actual = page.evaluate(function() {
1010 return $(".address:first").text();
1011 });
1012 if (actual != expected) {
1013 console.log("Address is not shown");
1014 console.log("Expected: " + expected);
1015 console.log("Got: " + actual);
1016 fail();
1017 }
1018 next();
1019 });
1020 });
1021 },
1022
1023 // Addresses are shown in order of derivation path
1024 function() {
1025 page.open(url, function(status) {
1026 // set the phrase
1027 page.evaluate(function() {
1028 $(".phrase").val("abandon abandon ability").trigger("input");
1029 });
1030 // get the derivation paths
1031 waitForGenerate(function() {
1032 var paths = page.evaluate(function() {
1033 return $(".index").map(function(i, e) {
1034 return $(e).text();
1035 });
1036 });
1037 if (paths.length != 20) {
1038 console.log("Total paths is less than expected: " + paths.length);
1039 fail();
1040 }
1041 for (var i=0; i<paths.length; i++) {
1042 var expected = "m/44'/0'/0'/0/" + i;
1043 var actual = paths[i];
1044 if (actual != expected) {
1045 console.log("Path " + i + " is incorrect");
1046 console.log("Expected: " + expected);
1047 console.log("Actual: " + actual);
1048 fail();
1049 }
1050 }
1051 next();
1052 });
1053 });
1054 },
1055
1056 // Address visibility can be toggled
1057 function() {
1058 page.open(url, function(status) {
1059 // set the phrase
1060 page.evaluate(function() {
1061 $(".phrase").val("abandon abandon ability");
1062 $(".phrase").trigger("input");
1063 });
1064 waitForGenerate(function() {
1065 // toggle address visibility
1066 page.evaluate(function() {
1067 $(".address-toggle").click();
1068 });
1069 // check the address is not visible
1070 var isInvisible = page.evaluate(function() {
1071 return $(".address:first span").hasClass("invisible");
1072 });
1073 if (!isInvisible) {
1074 console.log("Toggled address is visible");
1075 fail();
1076 }
1077 next();
1078 });
1079 });
1080 },
1081
1082 // Private key is shown
1083 // Private key visibility can be toggled
1084
1085 // More addresses can be generated
1086 // A custom number of additional addresses can be generated
1087 // Additional addresses are shown in order of derivation path
1088
1089 // BIP32 root key can be set by the user
1090 // Setting BIP32 root key clears the existing phrase, passphrase and seed
1091 // Clearing of phrase, passphrase and seed can be cancelled by user
1092 // Custom BIP32 root key is used when changing the derivation path
1093
1094 // Incorrect mnemonic shows error
1095 // Incorrect word shows suggested replacement
1096 // Incorrect BIP32 root key shows error
1097 // Derivation path not starting with m shows error
1098 // Derivation path containing invalid characters shows useful error
1099
1100 // Github Issue 11: Default word length is 15
1101 // https://github.com/dcpos/bip39/issues/11
1102
1103 // Github Issue 12: Generate more rows with private keys hidden
1104 // https://github.com/dcpos/bip39/issues/12
1105
1106 // Github Issue 19: Mnemonic is not sensitive to whitespace
1107 // https://github.com/dcpos/bip39/issues/19
1108
1109 // Github Issue 23: Use correct derivation path when changing tabs
1110 // https://github.com/dcpos/bip39/issues/23
1111
1112 // Github Issue 26: When using a Root key derrived altcoins are incorrect
1113 // https://github.com/dcpos/bip39/issues/26
1114
1115 ];
1116
1117 console.log("Running tests...");
1118 tests = shuffle(tests);
1119 next();