]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blame - tests.js
Entropy can be supplied by user
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / tests.js
CommitLineData
88e2cdaa
IC
1// Usage:
2// $ phantomjs tests.js
3
4
5var page = require('webpage').create();
6var url = 'src/index.html';
3eef9d0d 7var testMaxTime = 5000;
88e2cdaa
IC
8
9page.onResourceError = function(e) {
10 console.log("Error loading " + e.url);
11 phantom.exit();
12}
13
14function fail() {
15 console.log("Failed");
16 phantom.exit();
17}
18
3eef9d0d
IC
19function 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
c3719b00
IC
47function waitForFeedback(fn, maxTime) {
48 if (!maxTime) {
49 maxTime = testMaxTime;
50 }
51 var start = new Date().getTime();
52 var wait = function keepWaiting() {
53 var now = new Date().getTime();
54 var hasTimedOut = now - start > maxTime;
55 if (hasTimedOut) {
56 console.log("Test timed out");
57 fn();
58 return;
59 }
60 var feedback = page.evaluate(function() {
61 var feedback = $(".feedback");
62 if (feedback.css("display") == "none") {
63 return "";
64 }
65 return feedback.text();
66 });
67 var hasFinished = feedback.length > 0 && feedback != "Calculating...";
68 if (hasFinished) {
69 fn();
70 }
71 else {
72 setTimeout(keepWaiting, 100);
73 }
74 }
75 wait();
76}
77
88e2cdaa
IC
78function next() {
79 if (tests.length > 0) {
80 var testsStr = tests.length == 1 ? "test" : "tests";
81 console.log(tests.length + " " + testsStr + " remaining");
82 tests.shift()();
83 }
84 else {
85 console.log("Finished with 0 failures");
86 phantom.exit();
87 }
88}
89
fb372687
IC
90/**
91 * Randomize array element order in-place.
92 * Using Durstenfeld shuffle algorithm.
93 * See http://stackoverflow.com/a/12646864
94 */
95function shuffle(array) {
96 for (var i = array.length - 1; i > 0; i--) {
97 var j = Math.floor(Math.random() * (i + 1));
98 var temp = array[i];
99 array[i] = array[j];
100 array[j] = temp;
101 }
102 return array;
103}
104
88e2cdaa
IC
105tests = [
106
107// Page loads with status of 'success'
108function() {
109page.open(url, function(status) {
110 if (status != "success") {
111 console.log("Page did not load with status 'success'");
112 fail();
113 }
114 next();
115});
116},
117
118// Page has text
119function() {
120page.open(url, function(status) {
121 var content = page.evaluate(function() {
122 return document.body.textContent.trim();
123 });
124 if (!content) {
125 console.log("Page does not have text");
126 fail();
127 }
128 next();
129});
130},
131
132// Entering mnemonic generates addresses
133function() {
134page.open(url, function(status) {
88e2cdaa
IC
135 // set the phrase
136 page.evaluate(function() {
137 $(".phrase").val("abandon abandon ability").trigger("input");
138 });
139 // get the address
3eef9d0d 140 waitForGenerate(function() {
06c4c6e3
IC
141 var addressCount = page.evaluate(function() {
142 return $(".address").length;
88e2cdaa 143 });
06c4c6e3
IC
144 if (addressCount != 20) {
145 console.log("Mnemonic did not generate addresses");
88e2cdaa
IC
146 console.log("Expected: " + expected);
147 console.log("Got: " + actual);
148 fail();
149 }
150 next();
3eef9d0d 151 });
88e2cdaa
IC
152});
153},
154
155// Random button generates random mnemonic
156function() {
157page.open(url, function(status) {
158 // check initial phrase is empty
159 var phrase = page.evaluate(function() {
160 return $(".phrase").text();
161 });
162 if (phrase != "") {
163 console.log("Initial phrase is not blank");
164 fail();
165 }
166 // press the 'generate' button
167 page.evaluate(function() {
168 $(".generate").click();
169 });
170 // get the new phrase
3eef9d0d 171 waitForGenerate(function() {
88e2cdaa
IC
172 var phrase = page.evaluate(function() {
173 return $(".phrase").val();
174 });
175 if (phrase.length <= 0) {
176 console.log("Phrase not generated by pressing button");
177 fail();
178 }
179 next();
3eef9d0d 180 });
88e2cdaa
IC
181});
182},
183
184// Mnemonic length can be customized
185function() {
186page.open(url, function(status) {
187 // set the length to 6
54563907 188 var expectedLength = "6";
88e2cdaa 189 page.evaluate(function() {
54563907
IC
190 $(".strength option[selected]").removeAttr("selected");
191 $(".strength option[value=6]").prop("selected", true);
88e2cdaa
IC
192 });
193 // press the 'generate' button
194 page.evaluate(function() {
195 $(".generate").click();
196 });
197 // check the new phrase is six words long
3eef9d0d 198 waitForGenerate(function() {
88e2cdaa
IC
199 var actualLength = page.evaluate(function() {
200 var words = $(".phrase").val().split(" ");
201 return words.length;
202 });
203 if (actualLength != expectedLength) {
204 console.log("Phrase not generated with correct length");
205 console.log("Expected: " + expectedLength);
206 console.log("Actual: " + actualLength);
207 fail();
208 }
54563907 209 next();
3eef9d0d 210 });
88e2cdaa
IC
211});
212},
213
88e2cdaa 214// Passphrase can be set
54563907
IC
215function() {
216page.open(url, function(status) {
217 // set the phrase and passphrase
218 var expected = "15pJzUWPGzR7avffV9nY5by4PSgSKG9rba";
219 page.evaluate(function() {
220 $(".phrase").val("abandon abandon ability");
221 $(".passphrase").val("secure_passphrase").trigger("input");
222 });
223 // check the address is generated correctly
3eef9d0d 224 waitForGenerate(function() {
54563907
IC
225 var actual = page.evaluate(function() {
226 return $(".address:first").text();
227 });
228 if (actual != expected) {
229 console.log("Passphrase results in wrong address");
230 console.log("Expected: " + expected);
231 console.log("Actual: " + actual);
232 fail();
233 }
234 next();
3eef9d0d 235 });
54563907
IC
236});
237},
238
88e2cdaa 239// Network can be set to bitcoin testnet
54563907
IC
240function() {
241page.open(url, function(status) {
59193779 242 // set the phrase and coin
54563907
IC
243 var expected = "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi";
244 page.evaluate(function() {
245 $(".phrase").val("abandon abandon ability");
246 $(".phrase").trigger("input");
247 $(".network option[selected]").removeAttr("selected");
248 $(".network option[value=1]").prop("selected", true);
249 $(".network").trigger("change");
250 });
251 // check the address is generated correctly
3eef9d0d 252 waitForGenerate(function() {
54563907
IC
253 var actual = page.evaluate(function() {
254 return $(".address:first").text();
255 });
256 if (actual != expected) {
257 console.log("Bitcoin testnet address is incorrect");
258 console.log("Expected: " + expected);
259 console.log("Actual: " + actual);
260 fail();
261 }
262 next();
3eef9d0d 263 });
54563907
IC
264});
265},
266
88e2cdaa 267// Network can be set to litecoin
59193779
IC
268function() {
269page.open(url, function(status) {
270 // set the phrase and coin
271 var expected = "LQ4XU8RX2ULPmPq9FcUHdVmPVchP9nwXdn";
272 page.evaluate(function() {
273 $(".phrase").val("abandon abandon ability");
274 $(".phrase").trigger("input");
275 $(".network option[selected]").removeAttr("selected");
276 $(".network option[value=2]").prop("selected", true);
277 $(".network").trigger("change");
278 });
279 // check the address is generated correctly
3eef9d0d 280 waitForGenerate(function() {
59193779
IC
281 var actual = page.evaluate(function() {
282 return $(".address:first").text();
283 });
284 if (actual != expected) {
285 console.log("Litecoin address is incorrect");
286 console.log("Expected: " + expected);
287 console.log("Actual: " + actual);
288 fail();
289 }
290 next();
3eef9d0d 291 });
59193779
IC
292});
293},
294
88e2cdaa 295// Network can be set to dogecoin
59193779
IC
296function() {
297page.open(url, function(status) {
298 // set the phrase and coin
299 var expected = "DPQH2AtuzkVSG6ovjKk4jbUmZ6iXLpgbJA";
300 page.evaluate(function() {
301 $(".phrase").val("abandon abandon ability");
302 $(".phrase").trigger("input");
303 $(".network option[selected]").removeAttr("selected");
304 $(".network option[value=3]").prop("selected", true);
305 $(".network").trigger("change");
306 });
307 // check the address is generated correctly
3eef9d0d 308 waitForGenerate(function() {
59193779
IC
309 var actual = page.evaluate(function() {
310 return $(".address:first").text();
311 });
312 if (actual != expected) {
313 console.log("Dogecoin address is incorrect");
314 console.log("Expected: " + expected);
315 console.log("Actual: " + actual);
316 fail();
317 }
318 next();
3eef9d0d 319 });
59193779
IC
320});
321},
322
88e2cdaa 323// Network can be set to shadowcash
59193779
IC
324function() {
325page.open(url, function(status) {
326 // set the phrase and coin
327 var expected = "SiSZtfYAXEFvMm3XM8hmtkGDyViRwErtCG";
328 page.evaluate(function() {
329 $(".phrase").val("abandon abandon ability");
330 $(".phrase").trigger("input");
331 $(".network option[selected]").removeAttr("selected");
332 $(".network option[value=4]").prop("selected", true);
333 $(".network").trigger("change");
334 });
335 // check the address is generated correctly
3eef9d0d 336 waitForGenerate(function() {
59193779
IC
337 var actual = page.evaluate(function() {
338 return $(".address:first").text();
339 });
340 if (actual != expected) {
341 console.log("Shadowcash address is incorrect");
342 console.log("Expected: " + expected);
343 console.log("Actual: " + actual);
344 fail();
345 }
346 next();
3eef9d0d 347 });
59193779
IC
348});
349},
350
88e2cdaa 351// Network can be set to shadowcash testnet
59193779
IC
352function() {
353page.open(url, function(status) {
354 // set the phrase and coin
355 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
356 page.evaluate(function() {
357 $(".phrase").val("abandon abandon ability");
358 $(".phrase").trigger("input");
359 $(".network option[selected]").removeAttr("selected");
360 $(".network option[value=5]").prop("selected", true);
361 $(".network").trigger("change");
362 });
363 // check the address is generated correctly
3eef9d0d 364 waitForGenerate(function() {
59193779
IC
365 var actual = page.evaluate(function() {
366 return $(".address:first").text();
367 });
368 if (actual != expected) {
369 console.log("Shadowcash testnet address is incorrect");
370 console.log("Expected: " + expected);
371 console.log("Actual: " + actual);
372 fail();
373 }
374 next();
3eef9d0d 375 });
59193779
IC
376});
377},
378
88e2cdaa 379// Network can be set to viacoin
59193779
IC
380function() {
381page.open(url, function(status) {
382 // set the phrase and coin
383 var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
384 page.evaluate(function() {
385 $(".phrase").val("abandon abandon ability");
386 $(".phrase").trigger("input");
387 $(".network option[selected]").removeAttr("selected");
388 $(".network option[value=6]").prop("selected", true);
389 $(".network").trigger("change");
390 });
391 // check the address is generated correctly
3eef9d0d 392 waitForGenerate(function() {
59193779
IC
393 var actual = page.evaluate(function() {
394 return $(".address:first").text();
395 });
396 if (actual != expected) {
397 console.log("Viacoin address is incorrect");
398 console.log("Expected: " + expected);
399 console.log("Actual: " + actual);
400 fail();
401 }
402 next();
3eef9d0d 403 });
59193779
IC
404});
405},
406
88e2cdaa 407// Network can be set to viacoin testnet
59193779
IC
408function() {
409page.open(url, function(status) {
410 // set the phrase and coin
411 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
412 page.evaluate(function() {
413 $(".phrase").val("abandon abandon ability");
414 $(".phrase").trigger("input");
415 $(".network option[selected]").removeAttr("selected");
416 $(".network option[value=7]").prop("selected", true);
417 $(".network").trigger("change");
418 });
419 // check the address is generated correctly
3eef9d0d 420 waitForGenerate(function() {
59193779
IC
421 var actual = page.evaluate(function() {
422 return $(".address:first").text();
423 });
424 if (actual != expected) {
425 console.log("Viacoin testnet address is incorrect");
426 console.log("Expected: " + expected);
427 console.log("Actual: " + actual);
428 fail();
429 }
430 next();
3eef9d0d 431 });
59193779
IC
432});
433},
434
88e2cdaa 435// Network can be set to jumbucks
59193779
IC
436function() {
437page.open(url, function(status) {
438 // set the phrase and coin
439 var expected = "JLEXccwDXADK4RxBPkRez7mqsHVoJBEUew";
440 page.evaluate(function() {
441 $(".phrase").val("abandon abandon ability");
442 $(".phrase").trigger("input");
443 $(".network option[selected]").removeAttr("selected");
444 $(".network option[value=8]").prop("selected", true);
445 $(".network").trigger("change");
446 });
447 // check the address is generated correctly
3eef9d0d 448 waitForGenerate(function() {
59193779
IC
449 var actual = page.evaluate(function() {
450 return $(".address:first").text();
451 });
452 if (actual != expected) {
453 console.log("Jumbucks address is incorrect");
454 console.log("Expected: " + expected);
455 console.log("Actual: " + actual);
456 fail();
457 }
458 next();
3eef9d0d 459 });
59193779
IC
460});
461},
462
88e2cdaa 463// Network can be set to clam
59193779
IC
464function() {
465page.open(url, function(status) {
466 // set the phrase and coin
467 var expected = "xCp4sakjVx4pUAZ6cBCtuin8Ddb6U1sk9y";
468 page.evaluate(function() {
469 $(".phrase").val("abandon abandon ability");
470 $(".phrase").trigger("input");
471 $(".network option[selected]").removeAttr("selected");
472 $(".network option[value=9]").prop("selected", true);
473 $(".network").trigger("change");
474 });
475 // check the address is generated correctly
3eef9d0d 476 waitForGenerate(function() {
59193779
IC
477 var actual = page.evaluate(function() {
478 return $(".address:first").text();
479 });
480 if (actual != expected) {
481 console.log("CLAM address is incorrect");
482 console.log("Expected: " + expected);
483 console.log("Actual: " + actual);
484 fail();
f3fad1b5
IC
485 }
486 next();
487 });
488});
489},
490
491// Network can be set to dash
492function() {
493page.open(url, function(status) {
494 // set the phrase and coin
495 var expected = "XdbhtMuGsPSkE6bPdNTHoFSszQKmK4S5LT";
496 page.evaluate(function() {
497 $(".phrase").val("abandon abandon ability");
498 $(".phrase").trigger("input");
499 $(".network option[selected]").removeAttr("selected");
500 $(".network option[value=10]").prop("selected", true);
501 $(".network").trigger("change");
502 });
503 // check the address is generated correctly
504 waitForGenerate(function() {
505 var actual = page.evaluate(function() {
506 return $(".address:first").text();
507 });
508 if (actual != expected) {
509 console.log("DASH address is incorrect");
510 console.log("Expected: " + expected);
511 console.log("Actual: " + actual);
512 fail();
59193779 513 }
bfb3dab6
IC
514 next();
515 });
516});
517},
518
519// Network can be set to namecoin
520function() {
521page.open(url, function(status) {
522 // set the phrase and coin
523 var expected = "Mw2vK2Bvex1yYtYF6sfbEg2YGoUc98YUD2";
524 page.evaluate(function() {
525 $(".phrase").val("abandon abandon ability");
526 $(".phrase").trigger("input");
527 $(".network option[selected]").removeAttr("selected");
528 $(".network option[value=11]").prop("selected", true);
529 $(".network").trigger("change");
530 });
531 // check the address is generated correctly
532 waitForGenerate(function() {
533 var actual = page.evaluate(function() {
534 return $(".address:first").text();
535 });
536 if (actual != expected) {
537 console.log("Namecoin address is incorrect");
538 console.log("Expected: " + expected);
539 console.log("Actual: " + actual);
540 fail();
541 }
542 next();
543 });
544});
545},
546
547// Network can be set to peercoin
548function() {
549page.open(url, function(status) {
550 // set the phrase and coin
551 var expected = "PVAiioTaK2eDHSEo3tppT9AVdBYqxRTBAm";
552 page.evaluate(function() {
553 $(".phrase").val("abandon abandon ability");
554 $(".phrase").trigger("input");
555 $(".network option[selected]").removeAttr("selected");
556 $(".network option[value=12]").prop("selected", true);
557 $(".network").trigger("change");
558 });
559 // check the address is generated correctly
560 waitForGenerate(function() {
561 var actual = page.evaluate(function() {
562 return $(".address:first").text();
563 });
564 if (actual != expected) {
565 console.log("Peercoin address is incorrect");
566 console.log("Expected: " + expected);
567 console.log("Actual: " + actual);
568 fail();
569 }
59193779 570 next();
3eef9d0d 571 });
59193779
IC
572});
573},
574
88e2cdaa 575// BIP39 seed is set from phrase
c196ad55
IC
576function() {
577page.open(url, function(status) {
578 // set the phrase
579 var expected = "20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3";
580 page.evaluate(function() {
581 $(".phrase").val("abandon abandon ability");
582 $(".phrase").trigger("input");
583 });
584 // check the address is generated correctly
3eef9d0d 585 waitForGenerate(function() {
c196ad55
IC
586 var actual = page.evaluate(function() {
587 return $(".seed").val();
588 });
589 if (actual != expected) {
590 console.log("BIP39 seed is incorrectly generated from mnemonic");
591 console.log("Expected: " + expected);
592 console.log("Actual: " + actual);
593 fail();
594 }
595 next();
3eef9d0d 596 });
c196ad55
IC
597});
598},
599
88e2cdaa 600// BIP32 root key is set from phrase
ec60b662
IC
601function() {
602page.open(url, function(status) {
603 // set the phrase
604 var expected = "xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi";
605 page.evaluate(function() {
606 $(".phrase").val("abandon abandon ability");
607 $(".phrase").trigger("input");
608 });
609 // check the address is generated correctly
3eef9d0d 610 waitForGenerate(function() {
ec60b662
IC
611 var actual = page.evaluate(function() {
612 return $(".root-key").val();
613 });
614 if (actual != expected) {
615 console.log("Root key is incorrectly generated from mnemonic");
616 console.log("Expected: " + expected);
617 console.log("Actual: " + actual);
618 fail();
619 }
620 next();
3eef9d0d 621 });
ec60b662
IC
622});
623},
624
88e2cdaa 625// Tabs show correct addresses when changed
cf7258fd
IC
626function() {
627page.open(url, function(status) {
628 // set the phrase
629 var expected = "17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz";
630 page.evaluate(function() {
631 $(".phrase").val("abandon abandon ability");
632 $(".phrase").trigger("input");
633 });
634 // change tabs
635 waitForGenerate(function() {
636 page.evaluate(function() {
637 $("#bip32-tab a").click();
638 });
639 // check the address is generated correctly
640 waitForGenerate(function() {
641 var actual = page.evaluate(function() {
642 return $(".address:first").text();
643 });
644 if (actual != expected) {
645 console.log("Clicking tab generates incorrect address");
646 console.log("Expected: " + expected);
647 console.log("Actual: " + actual);
648 fail();
649 }
650 next();
651 });
652 });
653});
654},
88e2cdaa
IC
655
656// BIP44 derivation path is shown
d077e1e7
IC
657function() {
658page.open(url, function(status) {
659 // set the phrase
660 var expected = "m/44'/0'/0'/0";
661 page.evaluate(function() {
662 $(".phrase").val("abandon abandon ability");
663 $(".phrase").trigger("input");
664 });
665 // check the derivation path of the first address
666 waitForGenerate(function() {
667 var actual = page.evaluate(function() {
668 return $("#bip44 .path").val();
669 });
670 if (actual != expected) {
671 console.log("BIP44 derivation path is incorrect");
672 console.log("Expected: " + expected);
673 console.log("Actual: " + actual);
674 fail();
675 }
676 next();
677 });
678});
679},
680
88e2cdaa 681// BIP44 extended private key is shown
4fd2925d
IC
682function() {
683page.open(url, function(status) {
684 // set the phrase
685 var expected = "xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG";
686 page.evaluate(function() {
687 $(".phrase").val("abandon abandon ability");
688 $(".phrase").trigger("input");
689 });
06286adb 690 // check the BIP44 extended private key
4fd2925d
IC
691 waitForGenerate(function() {
692 var actual = page.evaluate(function() {
693 return $(".extended-priv-key").val();
694 });
695 if (actual != expected) {
696 console.log("BIP44 extended private key is incorrect");
697 console.log("Expected: " + expected);
698 console.log("Actual: " + actual);
699 fail();
700 }
701 next();
702 });
703});
704},
705
88e2cdaa 706// BIP44 extended public key is shown
39fd45bb
IC
707function() {
708page.open(url, function(status) {
709 // set the phrase
710 var expected = "xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM";
711 page.evaluate(function() {
712 $(".phrase").val("abandon abandon ability");
713 $(".phrase").trigger("input");
714 });
06286adb 715 // check the BIP44 extended public key
39fd45bb
IC
716 waitForGenerate(function() {
717 var actual = page.evaluate(function() {
718 return $(".extended-pub-key").val();
719 });
720 if (actual != expected) {
721 console.log("BIP44 extended public key is incorrect");
722 console.log("Expected: " + expected);
723 console.log("Actual: " + actual);
724 fail();
725 }
726 next();
727 });
728});
729},
730
06286adb
IC
731// BIP44 purpose field changes address list
732function() {
733page.open(url, function(status) {
734 // set the phrase
735 var expected = "1JbDzRJ2cDT8aat2xwKd6Pb2zzavow5MhF";
736 page.evaluate(function() {
737 $(".phrase").val("abandon abandon ability");
738 $(".phrase").trigger("input");
739 });
740 waitForGenerate(function() {
741 // change the bip44 purpose field to 45
742 page.evaluate(function() {
743 $("#bip44 .purpose").val("45");
744 $("#bip44 .purpose").trigger("input");
745 });
746 waitForGenerate(function() {
747 // check the address for the new derivation path
748 var actual = page.evaluate(function() {
749 return $(".address:first").text();
750 });
751 if (actual != expected) {
752 console.log("BIP44 purpose field generates incorrect address");
753 console.log("Expected: " + expected);
754 console.log("Actual: " + actual);
755 fail();
756 }
757 next();
758 });
759 });
760});
761},
762
88e2cdaa 763// BIP44 coin field changes address list
9eb72cdf
IC
764function() {
765page.open(url, function(status) {
766 // set the phrase
767 var expected = "1F6dB2djQYrxoyfZZmfr6D5voH8GkJTghk";
768 page.evaluate(function() {
769 $(".phrase").val("abandon abandon ability");
770 $(".phrase").trigger("input");
771 });
772 waitForGenerate(function() {
773 // change the bip44 purpose field to 45
774 page.evaluate(function() {
775 $("#bip44 .coin").val("1");
776 $("#bip44 .coin").trigger("input");
777 });
778 waitForGenerate(function() {
779 // check the address for the new derivation path
780 var actual = page.evaluate(function() {
781 return $(".address:first").text();
782 });
783 if (actual != expected) {
784 console.log("BIP44 coin field generates incorrect address");
785 console.log("Expected: " + expected);
786 console.log("Actual: " + actual);
787 fail();
788 }
789 next();
790 });
791 });
792});
793},
794
88e2cdaa 795// BIP44 account field changes address list
048bc3e0
IC
796function() {
797page.open(url, function(status) {
798 // set the phrase
799 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
800 page.evaluate(function() {
801 $(".phrase").val("abandon abandon ability");
802 $(".phrase").trigger("input");
803 });
804 waitForGenerate(function() {
805 // change the bip44 purpose field to 45
806 page.evaluate(function() {
807 $("#bip44 .account").val("1");
808 $("#bip44 .account").trigger("input");
809 });
810 waitForGenerate(function() {
811 // check the address for the new derivation path
812 var actual = page.evaluate(function() {
813 return $(".address:first").text();
814 });
815 if (actual != expected) {
816 console.log("BIP44 account field generates incorrect address");
817 console.log("Expected: " + expected);
818 console.log("Actual: " + actual);
819 fail();
820 }
821 next();
822 });
823 });
824});
825},
826
fa4da086
IC
827// BIP44 change field changes address list
828function() {
829page.open(url, function(status) {
830 // set the phrase
831 var expected = "1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo";
832 page.evaluate(function() {
833 $(".phrase").val("abandon abandon ability");
834 $(".phrase").trigger("input");
835 });
836 waitForGenerate(function() {
837 // change the bip44 purpose field to 45
838 page.evaluate(function() {
839 $("#bip44 .change").val("1");
840 $("#bip44 .change").trigger("input");
841 });
842 waitForGenerate(function() {
843 // check the address for the new derivation path
844 var actual = page.evaluate(function() {
845 return $(".address:first").text();
846 });
847 if (actual != expected) {
848 console.log("BIP44 change field generates incorrect address");
849 console.log("Expected: " + expected);
850 console.log("Actual: " + actual);
851 fail();
852 }
853 next();
854 });
855 });
856});
857},
048bc3e0 858
88e2cdaa 859// BIP32 derivation path can be set
651382a3
IC
860function() {
861page.open(url, function(status) {
862 // set the phrase
863 var expected = "16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L";
864 page.evaluate(function() {
865 $(".phrase").val("abandon abandon ability");
866 $(".phrase").trigger("input");
867 });
868 // change tabs
869 waitForGenerate(function() {
870 page.evaluate(function() {
871 $("#bip32-tab a").click();
872 });
873 // set the derivation path to m/1
874 waitForGenerate(function() {
875 page.evaluate(function() {
876 $("#bip32 .path").val("m/1");
877 $("#bip32 .path").trigger("input");
878 });
879 // check the address is generated correctly
880 waitForGenerate(function() {
881 var actual = page.evaluate(function() {
882 return $(".address:first").text();
883 });
884 if (actual != expected) {
885 console.log("Custom BIP32 path generates incorrect address");
886 console.log("Expected: " + expected);
887 console.log("Actual: " + actual);
888 fail();
889 }
890 next();
891 });
892 });
893 });
894});
895},
896
88e2cdaa 897// BIP32 can use hardened derivation paths
651382a3
IC
898function() {
899page.open(url, function(status) {
900 // set the phrase
901 var expected = "14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4";
902 page.evaluate(function() {
903 $(".phrase").val("abandon abandon ability");
904 $(".phrase").trigger("input");
905 });
906 // change tabs
907 waitForGenerate(function() {
908 page.evaluate(function() {
909 $("#bip32-tab a").click();
910 });
911 // set the derivation path to m/0'
912 waitForGenerate(function() {
913 page.evaluate(function() {
914 $("#bip32 .path").val("m/0'");
915 $("#bip32 .path").trigger("input");
916 });
917 // check the address is generated correctly
918 waitForGenerate(function() {
919 var actual = page.evaluate(function() {
920 return $(".address:first").text();
921 });
922 if (actual != expected) {
923 console.log("Hardened BIP32 path generates incorrect address");
924 console.log("Expected: " + expected);
925 console.log("Actual: " + actual);
926 fail();
927 }
928 next();
929 });
930 });
931 });
932});
933},
934
88e2cdaa 935// BIP32 extended private key is shown
9e9dcfda
IC
936function() {
937page.open(url, function(status) {
938 // set the phrase
939 var expected = "xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe";
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 private key is generated correctly
950 waitForGenerate(function() {
951 var actual = page.evaluate(function() {
952 return $(".extended-priv-key").val();
953 });
954 if (actual != expected) {
955 console.log("BIP32 extended private key is incorrect");
956 console.log("Expected: " + expected);
957 console.log("Actual: " + actual);
958 fail();
959 }
960 next();
961 });
962 });
963});
964},
965
88e2cdaa 966// BIP32 extended public key is shown
9e9dcfda
IC
967function() {
968page.open(url, function(status) {
969 // set the phrase
970 var expected = "xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P";
971 page.evaluate(function() {
972 $(".phrase").val("abandon abandon ability");
973 $(".phrase").trigger("input");
974 });
975 // change tabs
976 waitForGenerate(function() {
977 page.evaluate(function() {
978 $("#bip32-tab a").click();
979 });
980 // check the extended public key is generated correctly
981 waitForGenerate(function() {
982 var actual = page.evaluate(function() {
983 return $(".extended-pub-key").val();
984 });
985 if (actual != expected) {
986 console.log("BIP32 extended public key is incorrect");
987 console.log("Expected: " + expected);
988 console.log("Actual: " + actual);
989 fail();
990 }
991 next();
992 });
993 });
994});
995},
88e2cdaa
IC
996
997// Derivation path is shown in table
5f844c62
IC
998function() {
999page.open(url, function(status) {
1000 // set the phrase
1001 var expected = "m/44'/0'/0'/0/0";
1002 page.evaluate(function() {
1003 $(".phrase").val("abandon abandon ability");
1004 $(".phrase").trigger("input");
1005 });
1006 // check for derivation path in table
1007 waitForGenerate(function() {
1008 var actual = page.evaluate(function() {
1009 return $(".index:first").text();
1010 });
1011 if (actual != expected) {
1012 console.log("Derivation path shown incorrectly in table");
1013 console.log("Expected: " + expected);
1014 console.log("Actual: " + actual);
1015 fail();
1016 }
1017 next();
1018 });
1019});
1020},
1021
88e2cdaa 1022// Derivation path for address can be hardened
4974fd7f
IC
1023function() {
1024page.open(url, function(status) {
1025 // set the phrase
1026 var expected = "18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd";
1027 page.evaluate(function() {
1028 $(".phrase").val("abandon abandon ability");
1029 $(".phrase").trigger("input");
1030 });
1031 // change tabs
1032 waitForGenerate(function() {
1033 page.evaluate(function() {
1034 $("#bip32-tab a").click();
1035 });
1036 waitForGenerate(function() {
1037 // select the hardened addresses option
1038 page.evaluate(function() {
1039 $(".hardened-addresses").prop("checked", true);
1040 $(".hardened-addresses").trigger("change");
1041 });
1042 waitForGenerate(function() {
1043 // check the generated address is hardened
1044 var actual = page.evaluate(function() {
1045 return $(".address:first").text();
1046 });
1047 if (actual != expected) {
1048 console.log("Hardened address is incorrect");
1049 console.log("Expected: " + expected);
1050 console.log("Actual: " + actual);
1051 fail();
1052 }
1053 next();
1054 });
1055 });
1056 });
1057});
1058},
1059
88e2cdaa 1060// Derivation path visibility can be toggled
a775b5c6
IC
1061function() {
1062page.open(url, function(status) {
1063 // set the phrase
1064 page.evaluate(function() {
1065 $(".phrase").val("abandon abandon ability");
1066 $(".phrase").trigger("input");
1067 });
a775b5c6
IC
1068 waitForGenerate(function() {
1069 // toggle path visibility
1070 page.evaluate(function() {
1071 $(".index-toggle").click();
1072 });
1073 // check the path is not visible
1074 var isInvisible = page.evaluate(function() {
1075 return $(".index:first span").hasClass("invisible");
1076 });
1077 if (!isInvisible) {
1078 console.log("Toggled derivation path is visible");
1079 fail();
1080 }
1081 next();
1082 });
1083});
1084},
1085
88e2cdaa 1086// Address is shown
06c4c6e3
IC
1087function() {
1088page.open(url, function(status) {
1089 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1090 // set the phrase
1091 page.evaluate(function() {
1092 $(".phrase").val("abandon abandon ability").trigger("input");
1093 });
1094 // get the address
1095 waitForGenerate(function() {
1096 var actual = page.evaluate(function() {
1097 return $(".address:first").text();
1098 });
1099 if (actual != expected) {
1100 console.log("Address is not shown");
1101 console.log("Expected: " + expected);
1102 console.log("Got: " + actual);
1103 fail();
1104 }
1105 next();
1106 });
1107});
1108},
1109
88e2cdaa 1110// Addresses are shown in order of derivation path
3f1faa4d
IC
1111function() {
1112page.open(url, function(status) {
1113 // set the phrase
1114 page.evaluate(function() {
1115 $(".phrase").val("abandon abandon ability").trigger("input");
1116 });
1117 // get the derivation paths
1118 waitForGenerate(function() {
1119 var paths = page.evaluate(function() {
1120 return $(".index").map(function(i, e) {
1121 return $(e).text();
1122 });
1123 });
1124 if (paths.length != 20) {
1125 console.log("Total paths is less than expected: " + paths.length);
1126 fail();
1127 }
1128 for (var i=0; i<paths.length; i++) {
1129 var expected = "m/44'/0'/0'/0/" + i;
1130 var actual = paths[i];
1131 if (actual != expected) {
1132 console.log("Path " + i + " is incorrect");
1133 console.log("Expected: " + expected);
1134 console.log("Actual: " + actual);
1135 fail();
1136 }
1137 }
1138 next();
1139 });
1140});
1141},
21372fab 1142
88e2cdaa 1143// Address visibility can be toggled
21372fab
IC
1144function() {
1145page.open(url, function(status) {
1146 // set the phrase
1147 page.evaluate(function() {
1148 $(".phrase").val("abandon abandon ability");
1149 $(".phrase").trigger("input");
1150 });
1151 waitForGenerate(function() {
1152 // toggle address visibility
1153 page.evaluate(function() {
1154 $(".address-toggle").click();
1155 });
1156 // check the address is not visible
1157 var isInvisible = page.evaluate(function() {
1158 return $(".address:first span").hasClass("invisible");
1159 });
1160 if (!isInvisible) {
1161 console.log("Toggled address is visible");
1162 fail();
1163 }
1164 next();
1165 });
1166});
1167},
1168
1b12b2f5
IC
1169// Public key is shown
1170function() {
1171page.open(url, function(status) {
1172 var expected = "033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3";
1173 // set the phrase
1174 page.evaluate(function() {
1175 $(".phrase").val("abandon abandon ability").trigger("input");
1176 });
1177 // get the address
1178 waitForGenerate(function() {
1179 var actual = page.evaluate(function() {
1180 return $(".pubkey:first").text();
1181 });
1182 if (actual != expected) {
1183 console.log("Public key is not shown");
1184 console.log("Expected: " + expected);
1185 console.log("Got: " + actual);
1186 fail();
1187 }
1188 next();
1189 });
1190});
1191},
1192
1193// Public key visibility can be toggled
1194function() {
1195page.open(url, function(status) {
1196 // set the phrase
1197 page.evaluate(function() {
1198 $(".phrase").val("abandon abandon ability");
1199 $(".phrase").trigger("input");
1200 });
1201 waitForGenerate(function() {
1202 // toggle public key visibility
1203 page.evaluate(function() {
1204 $(".public-key-toggle").click();
1205 });
1206 // check the public key is not visible
1207 var isInvisible = page.evaluate(function() {
1208 return $(".pubkey:first span").hasClass("invisible");
1209 });
1210 if (!isInvisible) {
1211 console.log("Toggled public key is visible");
1212 fail();
1213 }
1214 next();
1215 });
1216});
1217},
1218
88e2cdaa 1219// Private key is shown
8cd5e231
IC
1220function() {
1221page.open(url, function(status) {
1222 var expected = "L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE";
1223 // set the phrase
1224 page.evaluate(function() {
1225 $(".phrase").val("abandon abandon ability").trigger("input");
1226 });
1227 // get the address
1228 waitForGenerate(function() {
1229 var actual = page.evaluate(function() {
1230 return $(".privkey:first").text();
1231 });
1232 if (actual != expected) {
1233 console.log("Private key is not shown");
1234 console.log("Expected: " + expected);
1235 console.log("Got: " + actual);
1236 fail();
1237 }
1238 next();
1239 });
1240});
1241},
1242
88e2cdaa 1243// Private key visibility can be toggled
6848d03b
IC
1244function() {
1245page.open(url, function(status) {
1246 // set the phrase
1247 page.evaluate(function() {
1248 $(".phrase").val("abandon abandon ability");
1249 $(".phrase").trigger("input");
1250 });
1251 waitForGenerate(function() {
1252 // toggle private key visibility
1253 page.evaluate(function() {
1254 $(".private-key-toggle").click();
1255 });
1256 // check the private key is not visible
1257 var isInvisible = page.evaluate(function() {
1258 return $(".privkey:first span").hasClass("invisible");
1259 });
1260 if (!isInvisible) {
1261 console.log("Toggled private key is visible");
1262 fail();
1263 }
1264 next();
1265 });
1266});
1267},
88e2cdaa
IC
1268
1269// More addresses can be generated
35631659
IC
1270function() {
1271page.open(url, function(status) {
1272 // set the phrase
1273 page.evaluate(function() {
1274 $(".phrase").val("abandon abandon ability");
1275 $(".phrase").trigger("input");
1276 });
1277 waitForGenerate(function() {
1278 // generate more addresses
1279 page.evaluate(function() {
1280 $(".more").click();
1281 });
1282 waitForGenerate(function() {
1283 // check there are more addresses
1284 var addressCount = page.evaluate(function() {
1285 return $(".address").length;
1286 });
1287 if (addressCount != 40) {
1288 console.log("More addresses cannot be generated");
1289 fail();
1290 }
1291 next();
1292 });
1293 });
1294});
1295},
1296
88e2cdaa 1297// A custom number of additional addresses can be generated
8a89b9da
IC
1298function() {
1299page.open(url, function(status) {
1300 // set the phrase
1301 page.evaluate(function() {
1302 $(".phrase").val("abandon abandon ability");
1303 $(".phrase").trigger("input");
1304 });
1305 waitForGenerate(function() {
1306 // get the current number of addresses
1307 var oldAddressCount = page.evaluate(function() {
1308 return $(".address").length;
1309 });
1310 // set a custom number of additional addresses
1311 page.evaluate(function() {
1312 $(".rows-to-add").val(1);
1313 });
1314 // generate more addresses
1315 page.evaluate(function() {
1316 $(".more").click();
1317 });
1318 waitForGenerate(function() {
1319 // check there are the correct number of addresses
1320 var newAddressCount = page.evaluate(function() {
1321 return $(".address").length;
1322 });
1323 if (newAddressCount - oldAddressCount != 1) {
1324 console.log("Number of additional addresses cannot be customized");
1325 console.log(newAddressCount)
1326 console.log(oldAddressCount)
1327 fail();
1328 }
1329 next();
1330 });
1331 });
1332});
1333},
1334
88e2cdaa 1335// Additional addresses are shown in order of derivation path
4d387bf5
IC
1336function() {
1337page.open(url, function(status) {
1338 // set the phrase
1339 page.evaluate(function() {
1340 $(".phrase").val("abandon abandon ability").trigger("input");
1341 });
1342 waitForGenerate(function() {
1343 // generate more addresses
1344 page.evaluate(function() {
1345 $(".more").click();
1346 });
1347 // get the derivation paths
1348 waitForGenerate(function() {
1349 var paths = page.evaluate(function() {
1350 return $(".index").map(function(i, e) {
1351 return $(e).text();
1352 });
1353 });
1354 if (paths.length != 40) {
1355 console.log("Total additional paths is less than expected: " + paths.length);
1356 fail();
1357 }
1358 for (var i=0; i<paths.length; i++) {
1359 var expected = "m/44'/0'/0'/0/" + i;
1360 var actual = paths[i];
1361 if (actual != expected) {
1362 console.log("Path " + i + " is not in correct order");
1363 console.log("Expected: " + expected);
1364 console.log("Actual: " + actual);
1365 fail();
1366 }
1367 }
1368 next();
1369 });
1370 });
1371});
1372},
88e2cdaa
IC
1373
1374// BIP32 root key can be set by the user
61ed16a9
IC
1375function() {
1376page.open(url, function(status) {
1377 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1378 // set the root key
1379 page.evaluate(function() {
1380 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1381 });
1382 waitForGenerate(function() {
1383 var actual = page.evaluate(function() {
1384 return $(".address:first").text();
1385 });
1386 if (actual != expected) {
bc324fd2 1387 console.log("Setting BIP32 root key results in wrong address");
61ed16a9
IC
1388 console.log("Expected: " + expected);
1389 console.log("Actual: " + actual);
1390 fail();
1391 }
1392 next();
1393 });
1394});
1395},
1396
54563907 1397// Setting BIP32 root key clears the existing phrase, passphrase and seed
bc324fd2
IC
1398function() {
1399page.open(url, function(status) {
1400 var expected = "";
1401 // set a mnemonic
1402 page.evaluate(function() {
1403 $(".phrase").val("A non-blank but invalid value");
1404 });
1405 // Accept any confirm dialogs
1406 page.onConfirm = function() {
1407 return true;
1408 };
1409 // set the root key
1410 page.evaluate(function() {
1411 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1412 });
1413 waitForGenerate(function() {
1414 var actual = page.evaluate(function() {
1415 return $(".phrase").val();
1416 });
1417 if (actual != expected) {
1418 console.log("Phrase not cleared when setting BIP32 root key");
1419 console.log("Expected: " + expected);
1420 console.log("Actual: " + actual);
1421 fail();
1422 }
1423 next();
1424 });
1425});
1426},
1427
54563907 1428// Clearing of phrase, passphrase and seed can be cancelled by user
abfbe450
IC
1429function() {
1430page.open(url, function(status) {
1431 var expected = "abandon abandon ability";
1432 // set a mnemonic
1433 page.evaluate(function() {
1434 $(".phrase").val("abandon abandon ability");
1435 });
1436 // Cancel any confirm dialogs
1437 page.onConfirm = function() {
1438 return false;
1439 };
1440 // set the root key
1441 page.evaluate(function() {
1442 $(".root-key").val("xprv9s21ZrQH143K3d3vzEDD3KpSKmxsZ3y7CqhAL1tinwtP6wqK4TKEKjpBuo6P2hUhB6ZENo7TTSRytiP857hBZVpBdk8PooFuRspE1eywwNZ").trigger("input");
1443 });
1444 var actual = page.evaluate(function() {
1445 return $(".phrase").val();
1446 });
1447 if (actual != expected) {
1448 console.log("Phrase not retained when cancelling changes to BIP32 root key");
1449 console.log("Expected: " + expected);
1450 console.log("Actual: " + actual);
1451 fail();
1452 }
1453 next();
1454});
1455},
7ff86d4c 1456
88e2cdaa 1457// Custom BIP32 root key is used when changing the derivation path
7ff86d4c
IC
1458function() {
1459page.open(url, function(status) {
1460 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
1461 // set the root key
1462 page.evaluate(function() {
1463 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1464 });
1465 waitForGenerate(function() {
1466 // change the derivation path
1467 page.evaluate(function() {
1468 $("#account").val("1").trigger("input");
1469 });
1470 // check the bip32 root key is used for derivation, not the blank phrase
1471 waitForGenerate(function() {
1472 var actual = page.evaluate(function() {
1473 return $(".address:first").text();
1474 });
1475 if (actual != expected) {
1476 console.log("Changing the derivation path does not use BIP32 root key");
1477 console.log("Expected: " + expected);
1478 console.log("Actual: " + actual);
1479 fail();
1480 }
1481 next();
1482 });
1483 });
1484});
1485},
88e2cdaa
IC
1486
1487// Incorrect mnemonic shows error
c3719b00
IC
1488function() {
1489page.open(url, function(status) {
1490 // set the root key
1491 page.evaluate(function() {
1492 $(".phrase").val("abandon abandon abandon").trigger("input");
1493 });
1494 waitForFeedback(function() {
1495 // check there is an error shown
1496 var feedback = page.evaluate(function() {
1497 return $(".feedback").text();
1498 });
1499 if (feedback.length <= 0) {
1500 console.log("Invalid mnemonic does not show error");
1501 fail();
1502 }
1503 next();
1504 });
1505});
1506},
1507
88e2cdaa 1508// Incorrect word shows suggested replacement
20f80cfa
IC
1509function() {
1510page.open(url, function(status) {
1511 // set the root key
1512 page.evaluate(function() {
1513 $(".phrase").val("abandon abandon abiliti").trigger("input");
1514 });
1515 // check there is a suggestion shown
1516 waitForFeedback(function() {
1517 var feedback = page.evaluate(function() {
1518 return $(".feedback").text();
1519 });
1520 if (feedback.indexOf("did you mean ability?") < 0) {
1521 console.log("Incorrect word does not show suggested replacement");
1522 console.log("Error: " + error);
1523 fail();
1524 }
1525 next();
1526 });
1527});
1528},
1529
88e2cdaa 1530// Incorrect BIP32 root key shows error
02f4a90e
IC
1531function() {
1532page.open(url, function(status) {
1533 // set the root key
1534 page.evaluate(function() {
1535 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj").trigger("input");
1536 });
1537 // check there is an error shown
1538 waitForFeedback(function() {
1539 var feedback = page.evaluate(function() {
1540 return $(".feedback").text();
1541 });
1542 if (feedback != "Invalid root key") {
1543 console.log("Invalid root key does not show error");
1544 console.log("Error: " + error);
1545 fail();
1546 }
1547 next();
1548 });
1549});
1550},
1551
88e2cdaa 1552// Derivation path not starting with m shows error
f976b541
IC
1553function() {
1554page.open(url, function(status) {
1555 // set the mnemonic phrase
1556 page.evaluate(function() {
1557 $(".phrase").val("abandon abandon ability").trigger("input");
1558 });
1559 waitForGenerate(function() {
1560 // select the bip32 tab so custom derivation path can be set
1561 page.evaluate(function() {
1562 $("#bip32-tab a").click();
1563 });
1564 waitForGenerate(function() {
1565 // set the incorrect derivation path
1566 page.evaluate(function() {
1567 $("#bip32 .path").val("n/0").trigger("input");
1568 });
1569 waitForFeedback(function() {
1570 var feedback = page.evaluate(function() {
1571 return $(".feedback").text();
1572 });
1573 if (feedback != "First character must be 'm'") {
1574 console.log("Derivation path not starting with m should show error");
1575 console.log("Error: " + error);
1576 fail();
1577 }
1578 next();
1579 });
1580 });
1581 });
1582});
1583},
1584
88e2cdaa 1585// Derivation path containing invalid characters shows useful error
55c0ffcb
IC
1586function() {
1587page.open(url, function(status) {
1588 // set the mnemonic phrase
1589 page.evaluate(function() {
1590 $(".phrase").val("abandon abandon ability").trigger("input");
1591 });
1592 waitForGenerate(function() {
1593 // select the bip32 tab so custom derivation path can be set
1594 page.evaluate(function() {
1595 $("#bip32-tab a").click();
1596 });
1597 waitForGenerate(function() {
1598 // set the incorrect derivation path
1599 page.evaluate(function() {
1600 $("#bip32 .path").val("m/1/0wrong1/1").trigger("input");
1601 });
1602 waitForFeedback(function() {
1603 var feedback = page.evaluate(function() {
1604 return $(".feedback").text();
1605 });
1606 if (feedback != "Invalid characters 0wrong1 found at depth 2") {
1607 console.log("Derivation path with invalid characters should show error");
1608 console.log("Error: " + error);
1609 fail();
1610 }
1611 next();
1612 });
1613 });
1614 });
1615});
1616},
88e2cdaa
IC
1617
1618// Github Issue 11: Default word length is 15
b630f83d 1619// https://github.com/iancoleman/bip39/issues/11
ca976aa9
IC
1620function() {
1621page.open(url, function(status) {
1622 // get the word length
1623 var defaultLength = page.evaluate(function() {
1624 return $(".strength").val();
1625 });
1626 if (defaultLength != 15) {
1627 console.log("Default word length is not 15");
1628 fail();
1629 }
1630 next();
1631});
1632},
1633
88e2cdaa
IC
1634
1635// Github Issue 12: Generate more rows with private keys hidden
b630f83d 1636// https://github.com/iancoleman/bip39/issues/12
c97627fa
IC
1637function() {
1638page.open(url, function(status) {
1639 // set the phrase
1640 page.evaluate(function() {
1641 $(".phrase").val("abandon abandon ability");
1642 $(".phrase").trigger("input");
1643 });
1644 waitForGenerate(function() {
1645 // toggle private keys hidden, then generate more addresses
1646 page.evaluate(function() {
1647 $(".private-key-toggle").click();
1648 $(".more").click();
1649 });
1650 waitForGenerate(function() {
1651 // check more have been generated
1652 var expected = 40;
1653 var numPrivKeys = page.evaluate(function() {
1654 return $(".privkey").length;
1655 });
1656 if (numPrivKeys != expected) {
1657 console.log("Wrong number of addresses when clicking 'more' with hidden privkeys");
1658 console.log("Expected: " + expected);
1659 console.log("Actual: " + numPrivKeys);
1660 fail();
1661 }
1662 // check no private keys are shown
1663 var numHiddenPrivKeys = page.evaluate(function() {
1664 return $(".privkey span[class=invisible]").length;
1665 });
1666 if (numHiddenPrivKeys != expected) {
1667 console.log("Generating more does not retain hidden state of privkeys");
1668 console.log("Expected: " + expected);
1669 console.log("Actual: " + numHiddenPrivKeys);
1670 fail();
1671 }
1672 next();
1673 });
1674 });
1675});
1676},
88e2cdaa
IC
1677
1678// Github Issue 19: Mnemonic is not sensitive to whitespace
b630f83d 1679// https://github.com/iancoleman/bip39/issues/19
a7becc43
IC
1680function() {
1681page.open(url, function(status) {
1682 // set the phrase
1683 var expected = "xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC";
1684 page.evaluate(function() {
1685 var doubleSpace = " ";
1686 $(".phrase").val("urge cat" + doubleSpace + "bid");
1687 $(".phrase").trigger("input");
1688 });
1689 waitForGenerate(function() {
1690 // Check the bip32 root key is correct
1691 var actual = page.evaluate(function() {
1692 return $(".root-key").val();
1693 });
1694 if (actual != expected) {
1695 console.log("Mnemonic is sensitive to whitespace");
1696 console.log("Expected: " + expected);
1697 console.log("Actual: " + actual);
1698 fail();
1699 }
1700 next();
1701 });
1702});
1703},
88e2cdaa 1704
e3001539 1705// Github Issue 23: Part 1: Use correct derivation path when changing tabs
b630f83d 1706// https://github.com/iancoleman/bip39/issues/23
e3001539
IC
1707function() {
1708page.open(url, function(status) {
1709 // 1) and 2) set the phrase
1710 page.evaluate(function() {
1711 $(".phrase").val("abandon abandon ability").trigger("input");
1712 });
1713 waitForGenerate(function() {
1714 // 3) select bip32 tab
1715 page.evaluate(function() {
1716 $("#bip32-tab a").click();
1717 });
1718 waitForGenerate(function() {
1719 // 4) switch from bitcoin to litecoin
1720 page.evaluate(function() {
1721 $(".network").val("2").trigger("change");
1722 });
1723 waitForGenerate(function() {
1724 // 5) Check derivation path is displayed correctly
1725 var expected = "m/0/0";
1726 var actual = page.evaluate(function() {
1727 return $(".index:first").text();
1728 });
1729 if (actual != expected) {
1730 console.log("Github Issue 23 Part 1: derivation path display error");
1731 console.log("Expected: " + expected);
1732 console.log("Actual: " + actual);
1733 fail();
1734 }
1735 // 5) Check address is displayed correctly
1736 var expected = "LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5";
1737 var actual = page.evaluate(function() {
1738 return $(".address:first").text();
1739 });
1740 if (actual != expected) {
1741 console.log("Github Issue 23 Part 1: address display error");
1742 console.log("Expected: " + expected);
1743 console.log("Actual: " + actual);
1744 fail();
1745 }
1746 next();
1747 });
1748 });
1749 });
1750});
1751},
1752
1753// Github Issue 23 Part 2: Coin selection in derivation path
b630f83d 1754// https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920
af4fd3a2
IC
1755function() {
1756page.open(url, function(status) {
1757 // set the phrase
1758 page.evaluate(function() {
1759 $(".phrase").val("abandon abandon ability").trigger("input");
1760 });
1761 waitForGenerate(function() {
1762 // switch from bitcoin to clam
1763 page.evaluate(function() {
1764 $(".network").val("9").trigger("change");
1765 });
1766 waitForGenerate(function() {
1767 // check derivation path is displayed correctly
1768 var expected = "m/44'/23'/0'/0/0";
1769 var actual = page.evaluate(function() {
1770 return $(".index:first").text();
1771 });
1772 if (actual != expected) {
1773 console.log("Github Issue 23 Part 2: Coin in BIP44 derivation path is incorrect");
1774 console.log("Expected: " + expected);
1775 console.log("Actual: " + actual);
1776 fail();
1777 }
1778 next();
1779 });
1780 });
1781});
1782},
88e2cdaa 1783
f3d0aca1 1784// Github Issue 26: When using a Root key derrived altcoins are incorrect
b630f83d 1785// https://github.com/iancoleman/bip39/issues/26
558ef9ac
IC
1786function() {
1787page.open(url, function(status) {
1788 // 1) 2) and 3) set the root key
1789 page.evaluate(function() {
1790 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1791 });
1792 waitForGenerate(function() {
1793 // 4) switch from bitcoin to viacoin
1794 page.evaluate(function() {
1795 $(".network").val("6").trigger("change");
1796 });
1797 waitForGenerate(function() {
1798 // 5) ensure the derived address is correct
1799 var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
1800 var actual = page.evaluate(function() {
1801 return $(".address:first").text();
1802 });
1803 if (actual != expected) {
1804 console.log("Github Issue 26: address is incorrect when changing networks and using root-key to derive");
1805 console.log("Expected: " + expected);
1806 console.log("Actual: " + actual);
1807 fail();
1808 }
1809 next();
1810 });
1811 });
1812});
1813},
f3d0aca1 1814
e1bae843
IC
1815// Selecting a language with no existing phrase should generate a phrase in
1816// that language.
1817function() {
1818page.open(url, function(status) {
1819 // Select a language
1820 // Need to manually simulate hash being set due to quirk between
1821 // 'click' event triggered by javascript vs triggered by mouse.
1822 // Perhaps look into page.sendEvent
1823 // http://phantomjs.org/api/webpage/method/send-event.html
1824 page.evaluate(function() {
1825 window.location.hash = "#japanese";
1826 $("a[href='#japanese']").trigger("click");
1827 });
1828 waitForGenerate(function() {
1829 // Check the mnemonic is in Japanese
1830 var phrase = page.evaluate(function() {
1831 return $(".phrase").val();
1832 });
1833 if (phrase.length <= 0) {
1834 console.log("No Japanese phrase generated");
1835 fail();
1836 }
1837 if (phrase.charCodeAt(0) < 128) {
1838 console.log("First character of Japanese phrase is ascii");
1839 console.log("Phrase: " + phrase);
1840 fail();
1841 }
1842 next();
1843 });
1844});
1845},
1846
1847// Selecting a language with existing phrase should update the phrase to use
1848// that language.
1849function() {
1850page.open(url, function(status) {
1851 // Set the phrase to an English phrase.
1852 page.evaluate(function() {
1853 $(".phrase").val("abandon abandon ability").trigger("input");
1854 });
1855 waitForGenerate(function() {
1856 // Change to Italian
1857 // Need to manually simulate hash being set due to quirk between
1858 // 'click' event triggered by javascript vs triggered by mouse.
1859 // Perhaps look into page.sendEvent
1860 // http://phantomjs.org/api/webpage/method/send-event.html
1861 page.evaluate(function() {
1862 window.location.hash = "#italian";
1863 $("a[href='#italian']").trigger("click");
1864 });
1865 waitForGenerate(function() {
1866 // Check only the language changes, not the phrase
1867 var expected = "abaco abaco abbaglio";
1868 var actual = page.evaluate(function() {
1869 return $(".phrase").val();
1870 });
1871 if (actual != expected) {
1872 console.log("Changing language with existing phrase");
1873 console.log("Expected: " + expected);
1874 console.log("Actual: " + actual);
1875 fail();
1876 }
1877 // Check the address is correct
1878 var expected = "1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV";
1879 var actual = page.evaluate(function() {
1880 return $(".address:first").text();
1881 });
1882 if (actual != expected) {
1883 console.log("Changing language generates incorrect address");
1884 console.log("Expected: " + expected);
1885 console.log("Actual: " + actual);
1886 fail();
1887 }
1888 next();
1889 });
1890 });
1891});
1892},
1893
1894// Suggested replacement for erroneous word in non-English language
1895function() {
1896page.open(url, function(status) {
1897 // Set an incorrect phrase in Italian
1898 page.evaluate(function() {
1899 $(".phrase").val("abaco abaco zbbaglio").trigger("input");
1900 });
1901 waitForFeedback(function() {
1902 // Check the suggestion is correct
1903 var feedback = page.evaluate(function() {
1904 return $(".feedback").text();
1905 });
1906 if (feedback.indexOf("did you mean abbaglio?") < 0) {
1907 console.log("Incorrect Italian word does not show suggested replacement");
1908 console.log("Error: " + error);
1909 fail();
1910 }
1911 next();
1912 });
1913});
1914},
1915
1916
1917// Japanese word does not break across lines.
1918// Point 2 from
1919// https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
1920function() {
1921page.open(url, function(status) {
1922 hasWordBreakCss = page.content.indexOf("word-break: keep-all;") > -1;
1923 if (!hasWordBreakCss) {
1924 console.log("Japanese words can break across lines mid-word");
1925 console.log("Check CSS for '.phrase { word-break: keep-all; }'");
1926 fail();
1927 }
1928 // Run the next test
1929 next();
1930});
1931},
1932
1933// Language can be specified at page load using hash value in url
1934function() {
1935page.open(url, function(status) {
1936 // Set the page hash as if it were on a fresh page load
1937 page.evaluate(function() {
1938 window.location.hash = "#japanese";
1939 });
1940 // Generate a random phrase
1941 page.evaluate(function() {
1942 $(".generate").trigger("click");
1943 });
1944 waitForGenerate(function() {
1945 // Check the phrase is in Japanese
1946 var phrase = page.evaluate(function() {
1947 return $(".phrase").val();
1948 });
1949 if (phrase.length <= 0) {
1950 console.log("No phrase generated using url hash");
1951 fail();
1952 }
1953 if (phrase.charCodeAt(0) < 128) {
1954 console.log("Language not detected from url hash on page load.");
1955 console.log("Phrase: " + phrase);
1956 fail();
1957 }
1958 next();
1959 });
1960});
1961},
1962
c6624d51
IC
1963// Entropy unit tests
1964function() {
1965page.open(url, function(status) {
1966 var error = page.evaluate(function() {
1967 var e;
1968 // binary entropy is detected
1969 e = Entropy.fromString("01010101");
1970 if (e.base.str != "binary") {
1971 return "Binary entropy not detected correctly";
1972 }
1973 // base6 entropy is detected
1974 e = Entropy.fromString("012345012345");
1975 if (e.base.str != "base 6") {
1976 return "base6 entropy not detected correctly";
1977 }
1978 // dice entropy is detected
1979 e = Entropy.fromString("123456123456");
1980 if (e.base.str != "base 6 (dice)") {
1981 return "dice entropy not detected correctly";
1982 }
1983 // base10 entropy is detected
1984 e = Entropy.fromString("0123456789");
1985 if (e.base.str != "base 10") {
1986 return "base10 entropy not detected correctly";
1987 }
1988 // hex entropy is detected
1989 e = Entropy.fromString("0123456789ABCDEF");
1990 if (e.base.str != "hexadecimal") {
1991 return "hexadecimal entropy not detected correctly";
1992 }
1993 // entropy is case insensitive
1994 e = Entropy.fromString("aBcDeF");
1995 if (e.cleanStr != "aBcDeF") {
1996 return "Entropy should not be case sensitive";
1997 }
1998 // dice entropy is converted to base6
1999 e = Entropy.fromString("123456");
2000 if (e.cleanStr != "012345") {
2001 return "Dice entropy is not automatically converted to base6";
2002 }
2003 // dice entropy is preferred to base6 if ambiguous
2004 e = Entropy.fromString("12345");
2005 if (e.base.str != "base 6 (dice)") {
2006 return "dice not used as default over base 6";
2007 }
2008 // unused characters are ignored
2009 e = Entropy.fromString("fghijkl");
2010 if (e.cleanStr != "f") {
2011 return "additional characters are not ignored";
2012 }
2013 // the lowest base is used by default
2014 // 7 could be decimal or hexadecimal, but should be detected as decimal
2015 e = Entropy.fromString("7");
2016 if (e.base.str != "base 10") {
2017 return "lowest base is not used";
2018 }
2019 // Hexadecimal representation is returned
2020 e = Entropy.fromString("1010");
2021 if (e.hexStr != "A") {
2022 return "Hexadecimal representation not returned";
2023 }
2024 // Leading zeros are retained
2025 e = Entropy.fromString("000A");
2026 if (e.cleanStr != "000A") {
2027 return "Leading zeros are not retained";
2028 }
2029 // Leading zeros are correctly preserved for hex in binary string
2030 e = Entropy.fromString("2A");
2031 if (e.binaryStr != "00101010") {
2032 return "Hex leading zeros are not correct in binary";
2033 }
2034 // Keyboard mashing results in weak entropy
2035 // Despite being a long string, it's less than 30 bits of entropy
2036 e = Entropy.fromString("aj;se ifj; ask,dfv js;ifj");
2037 if (e.binaryStr.length >= 30) {
2038 return "Keyboard mashing should produce weak entropy";
2039 }
2040 return false;
2041 });
2042 if (error) {
2043 console.log("Entropy unit tests");
2044 console.log(error);
2045 fail();
2046 };
2047 next();
2048});
2049},
2050
2051// Entropy can be entered by the user
2052function() {
2053page.open(url, function(status) {
2054 expected = {
2055 mnemonic: "abandon abandon ability",
2056 address: "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug",
2057 }
2058 // use entropy
2059 page.evaluate(function() {
2060 $(".use-entropy").prop("checked", true).trigger("change");
2061 $(".entropy").val("00000000 00000000 00000000 00000000").trigger("input");
2062 });
2063 // check the mnemonic is set and address is correct
2064 waitForGenerate(function() {
2065 var actual = page.evaluate(function() {
2066 return {
2067 address: $(".address:first").text(),
2068 mnemonic: $(".phrase").val(),
2069 }
2070 });
2071 if (actual.mnemonic != expected.mnemonic) {
2072 console.log("Entropy does not generate correct mnemonic");
2073 console.log("Expected: " + expected.mnemonic);
2074 console.log("Got: " + actual.mnemonic);
2075 fail();
2076 }
2077 if (actual.address != expected.address) {
2078 console.log("Entropy does not generate correct address");
2079 console.log("Expected: " + expected.address);
2080 console.log("Got: " + actual.address);
2081 fail();
2082 }
2083 next();
2084 });
2085});
2086},
2087
2088// A warning about entropy is shown to the user, with additional information
2089function() {
2090page.open(url, function(status) {
2091 // get text content from entropy sections of page
2092 var hasWarning = page.evaluate(function() {
2093 var entropyText = $(".entropy-container").text();
2094 var warning = "mnemonic may be insecure";
2095 if (entropyText.indexOf(warning) == -1) {
2096 return false;
2097 }
2098 var readMoreText = $("#entropy-notes").parent().text();
2099 var goodSources = "flipping a fair coin, rolling a fair dice, noise measurements etc";
2100 if (readMoreText.indexOf(goodSources) == -1) {
2101 return false;
2102 }
2103 return true;
2104 });
2105 // check the warnings and information are shown
2106 if (!hasWarning) {
2107 console.log("Page does not contain warning about using own entropy");
2108 fail();
2109 }
2110 next();
2111});
2112},
2113
2114// The types of entropy available are described to the user
2115function() {
2116page.open(url, function(status) {
2117 // get placeholder text for entropy field
2118 var placeholder = page.evaluate(function() {
2119 return $(".entropy").attr("placeholder");
2120 });
2121 var options = [
2122 "binary",
2123 "base 6",
2124 "dice",
2125 "base 10",
2126 "hexadecimal",
2127 ];
2128 for (var i=0; i<options.length; i++) {
2129 var option = options[i];
2130 if (placeholder.indexOf(option) == -1) {
2131 console.log("Available entropy type is not shown to user: " + option);
2132 fail();
2133 }
2134 }
2135 next();
2136});
2137},
2138
2139// The actual entropy used is shown to the user
2140function() {
2141page.open(url, function(status) {
2142 // use entropy
2143 var badEntropySource = page.evaluate(function() {
2144 var entropy = "Not A Very Good Entropy Source At All";
2145 $(".use-entropy").prop("checked", true).trigger("change");
2146 $(".entropy").val(entropy).trigger("input");
2147 });
2148 // check the actual entropy being used is shown
2149 waitForGenerate(function() {
2150 var expectedText = "AedEceAA";
2151 var entropyText = page.evaluate(function() {
2152 return $(".entropy-container").text();
2153 });
2154 if (entropyText.indexOf(expectedText) == -1) {
2155 console.log("Actual entropy used is not shown");
2156 fail();
2157 }
2158 next();
2159 });
2160});
2161},
2162
2163// Binary entropy can be entered
2164function() {
2165page.open(url, function(status) {
2166 // use entropy
2167 page.evaluate(function() {
2168 $(".use-entropy").prop("checked", true).trigger("change");
2169 $(".entropy").val("01").trigger("input");
2170 });
2171 // check the entropy is shown to be the correct type
2172 waitForGenerate(function() {
2173 var entropyText = page.evaluate(function() {
2174 return $(".entropy-container").text();
2175 });
2176 if (entropyText.indexOf("binary") == -1) {
2177 console.log("Binary entropy is not detected and presented to user");
2178 fail();
2179 }
2180 next();
2181 });
2182});
2183},
2184
2185// Base 6 entropy can be entered
2186function() {
2187page.open(url, function(status) {
2188 // use entropy
2189 page.evaluate(function() {
2190 $(".use-entropy").prop("checked", true).trigger("change");
2191 $(".entropy").val("012345").trigger("input");
2192 });
2193 // check the entropy is shown to be the correct type
2194 waitForGenerate(function() {
2195 var entropyText = page.evaluate(function() {
2196 return $(".entropy-container").text();
2197 });
2198 if (entropyText.indexOf("base 6") == -1) {
2199 console.log("Base 6 entropy is not detected and presented to user");
2200 fail();
2201 }
2202 next();
2203 });
2204});
2205},
2206
2207// Base 6 dice entropy can be entered
2208function() {
2209page.open(url, function(status) {
2210 // use entropy
2211 page.evaluate(function() {
2212 $(".use-entropy").prop("checked", true).trigger("change");
2213 $(".entropy").val("123456").trigger("input");
2214 });
2215 // check the entropy is shown to be the correct type
2216 waitForGenerate(function() {
2217 var entropyText = page.evaluate(function() {
2218 return $(".entropy-container").text();
2219 });
2220 if (entropyText.indexOf("dice") == -1) {
2221 console.log("Dice entropy is not detected and presented to user");
2222 fail();
2223 }
2224 next();
2225 });
2226});
2227},
2228
2229// Base 10 entropy can be entered
2230function() {
2231page.open(url, function(status) {
2232 // use entropy
2233 page.evaluate(function() {
2234 $(".use-entropy").prop("checked", true).trigger("change");
2235 $(".entropy").val("789").trigger("input");
2236 });
2237 // check the entropy is shown to be the correct type
2238 waitForGenerate(function() {
2239 var entropyText = page.evaluate(function() {
2240 return $(".entropy-container").text();
2241 });
2242 if (entropyText.indexOf("base 10") == -1) {
2243 console.log("Base 10 entropy is not detected and presented to user");
2244 fail();
2245 }
2246 next();
2247 });
2248});
2249},
2250
2251// Hexadecimal entropy can be entered
2252function() {
2253page.open(url, function(status) {
2254 // use entropy
2255 page.evaluate(function() {
2256 $(".use-entropy").prop("checked", true).trigger("change");
2257 $(".entropy").val("abcdef").trigger("input");
2258 });
2259 // check the entropy is shown to be the correct type
2260 waitForGenerate(function() {
2261 var entropyText = page.evaluate(function() {
2262 return $(".entropy-container").text();
2263 });
2264 if (entropyText.indexOf("hexadecimal") == -1) {
2265 console.log("Hexadecimal entropy is not detected and presented to user");
2266 fail();
2267 }
2268 next();
2269 });
2270});
2271},
2272
2273// Dice entropy value is shown as the converted base 6 value
2274function() {
2275page.open(url, function(status) {
2276 // use entropy
2277 page.evaluate(function() {
2278 $(".use-entropy").prop("checked", true).trigger("change");
2279 $(".entropy").val("123456").trigger("input");
2280 });
2281 // check the entropy is shown as base 6, not as the original dice value
2282 waitForGenerate(function() {
2283 var entropyText = page.evaluate(function() {
2284 return $(".entropy-container").text();
2285 });
2286 if (entropyText.indexOf("012345") == -1) {
2287 console.log("Dice entropy is not shown to user as base 6 value");
2288 fail();
2289 }
2290 if (entropyText.indexOf("123456") > -1) {
2291 console.log("Dice entropy value is shown instead of true base 6 value");
2292 fail();
2293 }
2294 next();
2295 });
2296});
2297},
2298
2299// The number of bits of entropy accumulated is shown
2300function() {
2301page.open(url, function(status) {
2302 var tests = {
2303 "0000 0000 0000 0000 0000": "20",
2304 "0": "1",
2305 "0000": "4",
2306 "6": "3",
2307 "7": "3",
2308 "8": "4",
2309 "F": "4",
2310 "29": "5",
2311 "0A": "8",
2312 "1A": "8", // hex is always multiple of 4 bits of entropy
2313 "2A": "8",
2314 "4A": "8",
2315 "8A": "8",
2316 "FA": "8",
2317 "000A": "16",
2318 "2220": "10",
2319 "2221": "9", // uses dice, so entropy is actually 1110
2320 "2227": "12",
2321 "222F": "16",
2322 "FFFF": "16",
2323 }
2324 // Arrange tests in array so last one can be easily detected
2325 var entropys = [];
2326 var results = [];
2327 for (var entropy in tests) {
2328 entropys.push(entropy);
2329 results.push(tests[entropy]);
2330 }
2331 // use entropy
2332 page.evaluate(function(e) {
2333 $(".use-entropy").prop("checked", true).trigger("change");
2334 });
2335 // Run each test
2336 var nextTest = function runNextTest(i) {
2337 var entropy = entropys[i];
2338 var expected = results[i];
2339 // set entropy
2340 page.evaluate(function(e) {
2341 $(".addresses").empty(); // bit of a hack, but needed for waitForGenerate
2342 $(".entropy").val(e).trigger("input");
2343 }, entropy);
2344 // check the number of bits of entropy is shown
2345 waitForGenerate(function() {
2346 var entropyText = page.evaluate(function() {
2347 return $(".entropy-container").text();
2348 });
2349 if (entropyText.indexOf("Have " + expected + " bits of entropy") == -1) {
2350 console.log("Accumulated entropy is not shown correctly for " + entropy);
2351 fail();
2352 }
2353 var isLastTest = i == results.length - 1;
2354 if (isLastTest) {
2355 next();
2356 }
2357 else {
2358 runNextTest(i+1);
2359 }
2360 });
2361 }
2362 nextTest(0);
2363});
2364},
2365
2366// The number of bits of entropy to reach the next mnemonic strength is shown
2367function() {
2368page.open(url, function(status) {
2369 // use entropy
2370 page.evaluate(function() {
2371 $(".use-entropy").prop("checked", true).trigger("change");
2372 $(".entropy").val("7654321").trigger("input");
2373 });
2374 // check the amount of additional entropy required is shown
2375 waitForGenerate(function() {
2376 var entropyText = page.evaluate(function() {
2377 return $(".entropy-container").text();
2378 });
2379 if (entropyText.indexOf("3 more base 10 chars required") == -1) {
2380 console.log("Additional entropy requirement is not shown");
2381 fail();
2382 }
2383 next();
2384 });
2385});
2386},
2387
2388// The next strength above 0-word mnemonics is considered extremely weak
2389// The next strength above 3-word mnemonics is considered very weak
2390// The next strength above 6-word mnemonics is considered weak
2391// The next strength above 9-word mnemonics is considered strong
2392// The next strength above 12-word mnemonics is considered very strong
2393// The next strength above 15-word mnemonics is considered extremely strong
2394function() {
2395page.open(url, function(status) {
2396 var tests = [
2397 {
2398 entropy: "A",
2399 words: 0,
2400 nextStrength: "an extremely weak",
2401 },
2402 {
2403 entropy: "AAAAAAAA",
2404 words: 3,
2405 nextStrength: "a very weak",
2406 },
2407 {
2408 entropy: "AAAAAAAA B",
2409 words: 3,
2410 nextStrength: "a very weak",
2411 },
2412 {
2413 entropy: "AAAAAAAA BBBBBBBB",
2414 words: 6,
2415 nextStrength: "a weak",
2416 },
2417 {
2418 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
2419 words: 9,
2420 nextStrength: "a strong",
2421 },
2422 {
2423 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
2424 words: 12,
2425 nextStrength: "a very strong",
2426 },
2427 {
2428 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE",
2429 words: 15,
2430 nextStrength: "an extremely strong",
2431 }
2432 ];
2433 // use entropy
2434 page.evaluate(function() {
2435 $(".use-entropy").prop("checked", true).trigger("change");
2436 });
2437 var nextTest = function runNextTest(i) {
2438 test = tests[i];
2439 page.evaluate(function(e) {
2440 $(".addresses").empty();
2441 $(".entropy").val(e).trigger("input");
2442 }, test.entropy);
2443 waitForGenerate(function() {
2444 // check the strength of the current mnemonic
2445 var mnemonic = page.evaluate(function() {
2446 return $(".phrase").val();
2447 });
2448 if (test.words == 0) {
2449 if (mnemonic.length > 0) {
2450 console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words);
2451 console.log("Mnemonic: " + mnemonic);
2452 fail();
2453 }
2454 }
2455 else {
2456 if (mnemonic.split(" ").length != test.words) {
2457 console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words);
2458 console.log("Mnemonic: " + mnemonic);
2459 fail();
2460 }
2461 }
2462 // check the strength of the next mnemonic is shown
2463 var entropyText = page.evaluate(function() {
2464 return $(".entropy-container").text();
2465 });
2466 if (entropyText.indexOf("required to generate " + test.nextStrength + " mnemonic") == -1) {
2467 console.log("Strength indicator for " + test.nextStrength + " mnemonic is incorrect");
2468 fail();
2469 }
2470 var isLastTest = i == tests.length - 1;
2471 if (isLastTest) {
2472 next();
2473 }
2474 else {
2475 runNextTest(i+1);
2476 }
2477 });
2478 }
2479 nextTest(0);
2480});
2481},
2482
2483// Entropy is truncated from the right
2484function() {
2485page.open(url, function(status) {
2486 var expected = "abandon abandon ability";
2487 // use entropy
2488 page.evaluate(function() {
2489 $(".use-entropy").prop("checked", true).trigger("change");
2490 var entropy = "00000000 00000000 00000000 00000000";
2491 entropy += "11111111 11111111 11111111 1111"; // Missing last byte, only first 8 bytes are used
2492 $(".entropy").val(entropy).trigger("input");
2493 });
2494 // check the entropy is truncated from the right
2495 waitForGenerate(function() {
2496 var actual = page.evaluate(function() {
2497 return $(".phrase").val();
2498 });
2499 if (actual != expected) {
2500 console.log("Entropy is not truncated from the right");
2501 console.log("Expected: " + expected);
2502 console.log("Got: " + actual);
2503 fail();
2504 }
2505 next();
2506 });
2507});
2508},
2509
2510// Very large entropy results in very long mnemonics
2511function() {
2512page.open(url, function(status) {
2513 // use entropy
2514 page.evaluate(function() {
2515 $(".use-entropy").prop("checked", true).trigger("change");
2516 var entropy = "";
2517 // Generate a very long entropy string
2518 for (var i=0; i<33; i++) {
2519 entropy += "AAAAAAAA"; // 3 words * 33 iterations = 99 words
2520 }
2521 $(".entropy").val(entropy).trigger("input");
2522 });
2523 // check the mnemonic is very long
2524 waitForGenerate(function() {
2525 var wordCount = page.evaluate(function() {
2526 return $(".phrase").val().split(" ").length;
2527 });
2528 if (wordCount != 99) {
2529 console.log("Large entropy does not generate long mnemonic");
2530 console.log("Expected 99 words, got " + wordCount);
2531 fail();
2532 }
2533 next();
2534 });
2535});
2536},
2537
2538// Is compatible with bip32jp entropy
2539// https://bip32jp.github.io/english/index.html
2540// NOTES:
2541// Is incompatible with:
2542// base 6 with leading zeros
2543// base 6 wth 12 words / 53 chars
2544// base 20
2545function() {
2546page.open(url, function(status) {
2547 var expected = "defy trip fatal jaguar mean rack rifle survey satisfy drift twist champion steel wife state furnace night consider glove olympic oblige donor novel left";
2548 // use entropy
2549 page.evaluate(function() {
2550 $(".use-entropy").prop("checked", true).trigger("change");
2551 var entropy = "123450123450123450123450123450123450123450123450123450123450123450123450123450123450123450123450123";
2552 $(".entropy").val(entropy).trigger("input");
2553 });
2554 // check the mnemonic matches the expected value from bip32jp
2555 waitForGenerate(function() {
2556 var actual = page.evaluate(function() {
2557 return $(".phrase").val();
2558 });
2559 if (actual != expected) {
2560 console.log("Mnemonic does not match bip32jp for base 6 entropy");
2561 console.log("Expected: " + expected);
2562 console.log("Got: " + actual);
2563 fail();
2564 }
2565 next();
2566 });
2567});
2568},
2569
b0fb45b9
IC
2570// If you wish to add more tests, do so here...
2571
2572// Here is a blank test template
2573/*
2574
2575function() {
2576page.open(url, function(status) {
2577 // Do something on the page
2578 page.evaluate(function() {
2579 $(".phrase").val("abandon abandon ability").trigger("input");
2580 });
2581 waitForGenerate(function() {
2582 // Check the result of doing the thing
2583 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
2584 var actual = page.evaluate(function() {
2585 return $(".address:first").text();
2586 });
2587 if (actual != expected) {
2588 console.log("A specific message about what failed");
2589 console.log("Expected: " + expected);
2590 console.log("Actual: " + actual);
2591 fail();
2592 }
2593 // Run the next test
2594 next();
2595 });
2596});
2597},
2598
2599*/
2600
88e2cdaa
IC
2601];
2602
2603console.log("Running tests...");
fb372687 2604tests = shuffle(tests);
88e2cdaa 2605next();