]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blame - tests.js
add test for GAME
[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';
ddeb8613 7var testMaxTime = 20000;
88e2cdaa 8
e00964cc
IC
9page.viewportSize = {
10 width: 1024,
11 height: 720
12};
13
88e2cdaa
IC
14page.onResourceError = function(e) {
15 console.log("Error loading " + e.url);
16 phantom.exit();
17}
18
19function fail() {
20 console.log("Failed");
21 phantom.exit();
22}
23
3eef9d0d
IC
24function waitForGenerate(fn, maxTime) {
25 if (!maxTime) {
26 maxTime = testMaxTime;
27 }
28 var start = new Date().getTime();
29 var prevAddressCount = -1;
30 var wait = function keepWaiting() {
31 var now = new Date().getTime();
32 var hasTimedOut = now - start > maxTime;
33 var addressCount = page.evaluate(function() {
34 return $(".address").length;
35 });
36 var hasFinished = addressCount > 0 && addressCount == prevAddressCount;
37 prevAddressCount = addressCount;
38 if (hasFinished) {
39 fn();
40 }
41 else if (hasTimedOut) {
42 console.log("Test timed out");
43 fn();
44 }
45 else {
46 setTimeout(keepWaiting, 100);
47 }
48 }
49 wait();
50}
51
c3719b00
IC
52function waitForFeedback(fn, maxTime) {
53 if (!maxTime) {
54 maxTime = testMaxTime;
55 }
56 var start = new Date().getTime();
57 var wait = function keepWaiting() {
58 var now = new Date().getTime();
59 var hasTimedOut = now - start > maxTime;
60 if (hasTimedOut) {
61 console.log("Test timed out");
62 fn();
63 return;
64 }
65 var feedback = page.evaluate(function() {
66 var feedback = $(".feedback");
67 if (feedback.css("display") == "none") {
68 return "";
69 }
70 return feedback.text();
71 });
72 var hasFinished = feedback.length > 0 && feedback != "Calculating...";
73 if (hasFinished) {
74 fn();
75 }
76 else {
77 setTimeout(keepWaiting, 100);
78 }
79 }
80 wait();
81}
82
057722b0
IC
83function waitForEntropyFeedback(fn, maxTime) {
84 if (!maxTime) {
85 maxTime = testMaxTime;
86 }
87 var origFeedback = page.evaluate(function() {
dd944906 88 return $(".entropy-container").text();
057722b0
IC
89 });
90 var start = new Date().getTime();
91 var wait = function keepWaiting() {
92 var now = new Date().getTime();
93 var hasTimedOut = now - start > maxTime;
94 if (hasTimedOut) {
95 console.log("Test timed out");
96 fn();
97 return;
98 }
99 var feedback = page.evaluate(function() {
dd944906 100 return $(".entropy-container").text();
057722b0
IC
101 });
102 var hasFinished = feedback != origFeedback;
103 if (hasFinished) {
104 fn();
105 }
106 else {
107 setTimeout(keepWaiting, 100);
108 }
109 }
110 wait();
111}
112
88e2cdaa
IC
113function next() {
114 if (tests.length > 0) {
115 var testsStr = tests.length == 1 ? "test" : "tests";
116 console.log(tests.length + " " + testsStr + " remaining");
117 tests.shift()();
118 }
119 else {
120 console.log("Finished with 0 failures");
121 phantom.exit();
122 }
123}
124
fb372687
IC
125/**
126 * Randomize array element order in-place.
127 * Using Durstenfeld shuffle algorithm.
128 * See http://stackoverflow.com/a/12646864
129 */
130function shuffle(array) {
131 for (var i = array.length - 1; i > 0; i--) {
132 var j = Math.floor(Math.random() * (i + 1));
133 var temp = array[i];
134 array[i] = array[j];
135 array[j] = temp;
136 }
137 return array;
138}
139
88e2cdaa
IC
140tests = [
141
142// Page loads with status of 'success'
143function() {
144page.open(url, function(status) {
145 if (status != "success") {
146 console.log("Page did not load with status 'success'");
147 fail();
148 }
149 next();
150});
151},
152
153// Page has text
154function() {
155page.open(url, function(status) {
156 var content = page.evaluate(function() {
157 return document.body.textContent.trim();
158 });
159 if (!content) {
160 console.log("Page does not have text");
161 fail();
162 }
163 next();
164});
165},
166
167// Entering mnemonic generates addresses
168function() {
169page.open(url, function(status) {
88e2cdaa
IC
170 // set the phrase
171 page.evaluate(function() {
172 $(".phrase").val("abandon abandon ability").trigger("input");
173 });
174 // get the address
3eef9d0d 175 waitForGenerate(function() {
06c4c6e3
IC
176 var addressCount = page.evaluate(function() {
177 return $(".address").length;
88e2cdaa 178 });
06c4c6e3
IC
179 if (addressCount != 20) {
180 console.log("Mnemonic did not generate addresses");
88e2cdaa
IC
181 console.log("Expected: " + expected);
182 console.log("Got: " + actual);
183 fail();
184 }
185 next();
3eef9d0d 186 });
88e2cdaa
IC
187});
188},
189
190// Random button generates random mnemonic
191function() {
192page.open(url, function(status) {
193 // check initial phrase is empty
194 var phrase = page.evaluate(function() {
195 return $(".phrase").text();
196 });
197 if (phrase != "") {
198 console.log("Initial phrase is not blank");
199 fail();
200 }
201 // press the 'generate' button
202 page.evaluate(function() {
203 $(".generate").click();
204 });
205 // get the new phrase
3eef9d0d 206 waitForGenerate(function() {
88e2cdaa
IC
207 var phrase = page.evaluate(function() {
208 return $(".phrase").val();
209 });
210 if (phrase.length <= 0) {
211 console.log("Phrase not generated by pressing button");
212 fail();
213 }
214 next();
3eef9d0d 215 });
88e2cdaa
IC
216});
217},
218
219// Mnemonic length can be customized
220function() {
221page.open(url, function(status) {
222 // set the length to 6
54563907 223 var expectedLength = "6";
88e2cdaa 224 page.evaluate(function() {
54563907
IC
225 $(".strength option[selected]").removeAttr("selected");
226 $(".strength option[value=6]").prop("selected", true);
88e2cdaa
IC
227 });
228 // press the 'generate' button
229 page.evaluate(function() {
230 $(".generate").click();
231 });
232 // check the new phrase is six words long
3eef9d0d 233 waitForGenerate(function() {
88e2cdaa
IC
234 var actualLength = page.evaluate(function() {
235 var words = $(".phrase").val().split(" ");
236 return words.length;
237 });
238 if (actualLength != expectedLength) {
239 console.log("Phrase not generated with correct length");
240 console.log("Expected: " + expectedLength);
241 console.log("Actual: " + actualLength);
242 fail();
243 }
54563907 244 next();
3eef9d0d 245 });
88e2cdaa
IC
246});
247},
248
88e2cdaa 249// Passphrase can be set
54563907
IC
250function() {
251page.open(url, function(status) {
252 // set the phrase and passphrase
253 var expected = "15pJzUWPGzR7avffV9nY5by4PSgSKG9rba";
254 page.evaluate(function() {
255 $(".phrase").val("abandon abandon ability");
256 $(".passphrase").val("secure_passphrase").trigger("input");
257 });
258 // check the address is generated correctly
3eef9d0d 259 waitForGenerate(function() {
54563907
IC
260 var actual = page.evaluate(function() {
261 return $(".address:first").text();
262 });
263 if (actual != expected) {
264 console.log("Passphrase results in wrong address");
265 console.log("Expected: " + expected);
266 console.log("Actual: " + actual);
267 fail();
268 }
269 next();
3eef9d0d 270 });
54563907
IC
271});
272},
273
88e2cdaa 274// Network can be set to bitcoin testnet
54563907
IC
275function() {
276page.open(url, function(status) {
59193779 277 // set the phrase and coin
54563907
IC
278 var expected = "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi";
279 page.evaluate(function() {
280 $(".phrase").val("abandon abandon ability");
281 $(".phrase").trigger("input");
282 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
283 $(".network option").filter(function() {
284 return $(this).html() == "Bitcoin Testnet";
285 }).prop("selected", true);
54563907
IC
286 $(".network").trigger("change");
287 });
288 // check the address is generated correctly
3eef9d0d 289 waitForGenerate(function() {
54563907
IC
290 var actual = page.evaluate(function() {
291 return $(".address:first").text();
292 });
293 if (actual != expected) {
294 console.log("Bitcoin testnet address is incorrect");
295 console.log("Expected: " + expected);
296 console.log("Actual: " + actual);
297 fail();
298 }
299 next();
3eef9d0d 300 });
54563907
IC
301});
302},
303
88e2cdaa 304// Network can be set to litecoin
59193779
IC
305function() {
306page.open(url, function(status) {
307 // set the phrase and coin
308 var expected = "LQ4XU8RX2ULPmPq9FcUHdVmPVchP9nwXdn";
309 page.evaluate(function() {
310 $(".phrase").val("abandon abandon ability");
311 $(".phrase").trigger("input");
312 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
313 $(".network option").filter(function() {
314 return $(this).html() == "Litecoin";
315 }).prop("selected", true);
59193779
IC
316 $(".network").trigger("change");
317 });
318 // check the address is generated correctly
3eef9d0d 319 waitForGenerate(function() {
59193779
IC
320 var actual = page.evaluate(function() {
321 return $(".address:first").text();
322 });
323 if (actual != expected) {
324 console.log("Litecoin address is incorrect");
325 console.log("Expected: " + expected);
326 console.log("Actual: " + actual);
327 fail();
328 }
329 next();
3eef9d0d 330 });
59193779
IC
331});
332},
333
88e2cdaa 334// Network can be set to dogecoin
59193779
IC
335function() {
336page.open(url, function(status) {
337 // set the phrase and coin
338 var expected = "DPQH2AtuzkVSG6ovjKk4jbUmZ6iXLpgbJA";
339 page.evaluate(function() {
340 $(".phrase").val("abandon abandon ability");
341 $(".phrase").trigger("input");
342 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
343 $(".network option").filter(function() {
344 return $(this).html() == "Dogecoin";
345 }).prop("selected", true);
59193779
IC
346 $(".network").trigger("change");
347 });
348 // check the address is generated correctly
3eef9d0d 349 waitForGenerate(function() {
59193779
IC
350 var actual = page.evaluate(function() {
351 return $(".address:first").text();
352 });
353 if (actual != expected) {
354 console.log("Dogecoin address is incorrect");
355 console.log("Expected: " + expected);
356 console.log("Actual: " + actual);
357 fail();
358 }
359 next();
3eef9d0d 360 });
59193779
IC
361});
362},
363
88e2cdaa 364// Network can be set to shadowcash
59193779
IC
365function() {
366page.open(url, function(status) {
367 // set the phrase and coin
368 var expected = "SiSZtfYAXEFvMm3XM8hmtkGDyViRwErtCG";
369 page.evaluate(function() {
370 $(".phrase").val("abandon abandon ability");
371 $(".phrase").trigger("input");
372 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
373 $(".network option").filter(function() {
374 return $(this).html() == "ShadowCash";
375 }).prop("selected", true);
59193779
IC
376 $(".network").trigger("change");
377 });
378 // check the address is generated correctly
3eef9d0d 379 waitForGenerate(function() {
59193779
IC
380 var actual = page.evaluate(function() {
381 return $(".address:first").text();
382 });
383 if (actual != expected) {
384 console.log("Shadowcash address is incorrect");
385 console.log("Expected: " + expected);
386 console.log("Actual: " + actual);
387 fail();
388 }
389 next();
3eef9d0d 390 });
59193779
IC
391});
392},
393
88e2cdaa 394// Network can be set to shadowcash testnet
59193779
IC
395function() {
396page.open(url, function(status) {
397 // set the phrase and coin
398 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
399 page.evaluate(function() {
400 $(".phrase").val("abandon abandon ability");
401 $(".phrase").trigger("input");
402 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
403 $(".network option").filter(function() {
404 return $(this).html() == "ShadowCash Testnet";
405 }).prop("selected", true);
59193779
IC
406 $(".network").trigger("change");
407 });
408 // check the address is generated correctly
3eef9d0d 409 waitForGenerate(function() {
59193779
IC
410 var actual = page.evaluate(function() {
411 return $(".address:first").text();
412 });
413 if (actual != expected) {
414 console.log("Shadowcash testnet address is incorrect");
415 console.log("Expected: " + expected);
416 console.log("Actual: " + actual);
417 fail();
418 }
419 next();
3eef9d0d 420 });
59193779
IC
421});
422},
423
88e2cdaa 424// Network can be set to viacoin
59193779
IC
425function() {
426page.open(url, function(status) {
427 // set the phrase and coin
428 var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
429 page.evaluate(function() {
430 $(".phrase").val("abandon abandon ability");
431 $(".phrase").trigger("input");
432 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
433 $(".network option").filter(function() {
434 return $(this).html() == "Viacoin";
435 }).prop("selected", true);
59193779
IC
436 $(".network").trigger("change");
437 });
438 // check the address is generated correctly
3eef9d0d 439 waitForGenerate(function() {
59193779
IC
440 var actual = page.evaluate(function() {
441 return $(".address:first").text();
442 });
443 if (actual != expected) {
444 console.log("Viacoin address is incorrect");
445 console.log("Expected: " + expected);
446 console.log("Actual: " + actual);
447 fail();
448 }
449 next();
3eef9d0d 450 });
59193779
IC
451});
452},
453
88e2cdaa 454// Network can be set to viacoin testnet
59193779
IC
455function() {
456page.open(url, function(status) {
457 // set the phrase and coin
458 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
459 page.evaluate(function() {
460 $(".phrase").val("abandon abandon ability");
461 $(".phrase").trigger("input");
462 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
463 $(".network option").filter(function() {
464 return $(this).html() == "Viacoin Testnet";
465 }).prop("selected", true);
59193779
IC
466 $(".network").trigger("change");
467 });
468 // check the address is generated correctly
3eef9d0d 469 waitForGenerate(function() {
59193779
IC
470 var actual = page.evaluate(function() {
471 return $(".address:first").text();
472 });
473 if (actual != expected) {
474 console.log("Viacoin testnet address is incorrect");
475 console.log("Expected: " + expected);
476 console.log("Actual: " + actual);
477 fail();
478 }
479 next();
3eef9d0d 480 });
59193779
IC
481});
482},
483
88e2cdaa 484// Network can be set to jumbucks
59193779
IC
485function() {
486page.open(url, function(status) {
487 // set the phrase and coin
488 var expected = "JLEXccwDXADK4RxBPkRez7mqsHVoJBEUew";
489 page.evaluate(function() {
490 $(".phrase").val("abandon abandon ability");
491 $(".phrase").trigger("input");
492 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
493 $(".network option").filter(function() {
494 return $(this).html() == "Jumbucks";
495 }).prop("selected", true);
59193779
IC
496 $(".network").trigger("change");
497 });
498 // check the address is generated correctly
3eef9d0d 499 waitForGenerate(function() {
59193779
IC
500 var actual = page.evaluate(function() {
501 return $(".address:first").text();
502 });
503 if (actual != expected) {
504 console.log("Jumbucks address is incorrect");
505 console.log("Expected: " + expected);
506 console.log("Actual: " + actual);
507 fail();
508 }
509 next();
3eef9d0d 510 });
59193779
IC
511});
512},
513
88e2cdaa 514// Network can be set to clam
59193779
IC
515function() {
516page.open(url, function(status) {
517 // set the phrase and coin
518 var expected = "xCp4sakjVx4pUAZ6cBCtuin8Ddb6U1sk9y";
519 page.evaluate(function() {
520 $(".phrase").val("abandon abandon ability");
521 $(".phrase").trigger("input");
522 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
523 $(".network option").filter(function() {
524 return $(this).html() == "CLAM";
525 }).prop("selected", true);
59193779
IC
526 $(".network").trigger("change");
527 });
528 // check the address is generated correctly
3eef9d0d 529 waitForGenerate(function() {
59193779
IC
530 var actual = page.evaluate(function() {
531 return $(".address:first").text();
532 });
533 if (actual != expected) {
534 console.log("CLAM address is incorrect");
535 console.log("Expected: " + expected);
536 console.log("Actual: " + actual);
537 fail();
f3fad1b5
IC
538 }
539 next();
540 });
541});
542},
543
544// Network can be set to dash
545function() {
546page.open(url, function(status) {
547 // set the phrase and coin
548 var expected = "XdbhtMuGsPSkE6bPdNTHoFSszQKmK4S5LT";
549 page.evaluate(function() {
550 $(".phrase").val("abandon abandon ability");
551 $(".phrase").trigger("input");
552 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
553 $(".network option").filter(function() {
554 return $(this).html() == "DASH";
555 }).prop("selected", true);
f3fad1b5
IC
556 $(".network").trigger("change");
557 });
558 // check the address is generated correctly
559 waitForGenerate(function() {
560 var actual = page.evaluate(function() {
561 return $(".address:first").text();
562 });
563 if (actual != expected) {
564 console.log("DASH address is incorrect");
565 console.log("Expected: " + expected);
566 console.log("Actual: " + actual);
567 fail();
00fd1a03 568 }
569 next();
570 });
571});
572},
573
574// Network can be set to game
575function() {
576page.open(url, function(status) {
577 // set the phrase and coin
578 var expected = "GSMY9bAp36cMR4zyT4uGVS7GFjpdXbao5Q";
579 page.evaluate(function() {
580 $(".phrase").val("abandon abandon ability");
581 $(".phrase").trigger("input");
582 $(".network option[selected]").removeAttr("selected");
583 $(".network option").filter(function() {
584 return $(this).html() == "GAME";
585 }).prop("selected", true);
586 $(".network").trigger("change");
587 });
588 // check the address is generated correctly
589 waitForGenerate(function() {
590 var actual = page.evaluate(function() {
591 return $(".address:first").text();
592 });
593 if (actual != expected) {
594 console.log("GAME address is incorrect");
595 console.log("Expected: " + expected);
596 console.log("Actual: " + actual);
597 fail();
59193779 598 }
bfb3dab6
IC
599 next();
600 });
601});
602},
603
604// Network can be set to namecoin
605function() {
606page.open(url, function(status) {
607 // set the phrase and coin
608 var expected = "Mw2vK2Bvex1yYtYF6sfbEg2YGoUc98YUD2";
609 page.evaluate(function() {
610 $(".phrase").val("abandon abandon ability");
611 $(".phrase").trigger("input");
612 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
613 $(".network option").filter(function() {
614 return $(this).html() == "Namecoin";
615 }).prop("selected", true);
bfb3dab6
IC
616 $(".network").trigger("change");
617 });
618 // check the address is generated correctly
619 waitForGenerate(function() {
620 var actual = page.evaluate(function() {
621 return $(".address:first").text();
622 });
623 if (actual != expected) {
624 console.log("Namecoin address is incorrect");
625 console.log("Expected: " + expected);
626 console.log("Actual: " + actual);
627 fail();
628 }
629 next();
630 });
631});
632},
633
634// Network can be set to peercoin
635function() {
636page.open(url, function(status) {
637 // set the phrase and coin
638 var expected = "PVAiioTaK2eDHSEo3tppT9AVdBYqxRTBAm";
639 page.evaluate(function() {
640 $(".phrase").val("abandon abandon ability");
641 $(".phrase").trigger("input");
642 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
643 $(".network option").filter(function() {
644 return $(this).html() == "Peercoin";
645 }).prop("selected", true);
bfb3dab6
IC
646 $(".network").trigger("change");
647 });
648 // check the address is generated correctly
649 waitForGenerate(function() {
650 var actual = page.evaluate(function() {
651 return $(".address:first").text();
652 });
653 if (actual != expected) {
654 console.log("Peercoin address is incorrect");
655 console.log("Expected: " + expected);
656 console.log("Actual: " + actual);
657 fail();
658 }
59193779 659 next();
3eef9d0d 660 });
59193779
IC
661});
662},
663
24137d96
IC
664// Network can be set to ethereum
665function() {
666
667page.open(url, function(status) {
668
669 // set the phrase and coin
670 page.evaluate(function() {
671 $(".phrase").val("abandon abandon ability");
672 $(".phrase").trigger("input");
673 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
674 $(".network option").filter(function() {
675 return $(this).html() == "Ethereum";
676 }).prop("selected", true);
24137d96
IC
677 $(".network").trigger("change");
678 });
679 waitForGenerate(function() {
680 // check the address is generated correctly
681 // this value comes from
682 // https://www.myetherwallet.com/#view-wallet-info
49b21f12 683 // Unusual capitalization is due to checksum
24137d96
IC
684 var expected = "0xe5815d5902Ad612d49283DEdEc02100Bd44C2772";
685 var actual = page.evaluate(function() {
686 return $(".address:first").text();
687 });
49b21f12 688 if (actual != expected) {
24137d96
IC
689 console.log("Ethereum address is incorrect");
690 console.log("Expected: " + expected);
691 console.log("Actual: " + actual);
692 fail();
693 }
694 // check the private key is correct
695 // this private key can be imported into
696 // https://www.myetherwallet.com/#view-wallet-info
697 // and it should correlate to the address above
698 var expected = "8f253078b73d7498302bb78c171b23ce7a8fb511987d2b2702b731638a4a15e7";
699 var actual = page.evaluate(function() {
700 return $(".privkey:first").text();
701 });
702 if (actual != expected) {
703 console.log("Ethereum privkey is incorrect");
704 console.log("Expected: " + expected);
705 console.log("Actual: " + actual);
706 fail();
707 }
708 // check the public key is correct
709 // TODO
710 // don't have any third-party source to generate the expected value
711 //var expected = "?";
712 //var actual = page.evaluate(function() {
713 // return $(".pubkey:first").text();
714 //});
715 //if (actual != expected) {
716 // console.log("Ethereum privkey is incorrect");
717 // console.log("Expected: " + expected);
718 // console.log("Actual: " + actual);
719 // fail();
720 //}
721 next();
722 });
723});
724},
725
88e2cdaa 726// BIP39 seed is set from phrase
c196ad55
IC
727function() {
728page.open(url, function(status) {
729 // set the phrase
730 var expected = "20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3";
731 page.evaluate(function() {
732 $(".phrase").val("abandon abandon ability");
733 $(".phrase").trigger("input");
734 });
735 // check the address is generated correctly
3eef9d0d 736 waitForGenerate(function() {
c196ad55
IC
737 var actual = page.evaluate(function() {
738 return $(".seed").val();
739 });
740 if (actual != expected) {
741 console.log("BIP39 seed is incorrectly generated from mnemonic");
742 console.log("Expected: " + expected);
743 console.log("Actual: " + actual);
744 fail();
745 }
746 next();
3eef9d0d 747 });
c196ad55
IC
748});
749},
750
88e2cdaa 751// BIP32 root key is set from phrase
ec60b662
IC
752function() {
753page.open(url, function(status) {
754 // set the phrase
755 var expected = "xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi";
756 page.evaluate(function() {
757 $(".phrase").val("abandon abandon ability");
758 $(".phrase").trigger("input");
759 });
760 // check the address is generated correctly
3eef9d0d 761 waitForGenerate(function() {
ec60b662
IC
762 var actual = page.evaluate(function() {
763 return $(".root-key").val();
764 });
765 if (actual != expected) {
766 console.log("Root key is incorrectly generated from mnemonic");
767 console.log("Expected: " + expected);
768 console.log("Actual: " + actual);
769 fail();
770 }
771 next();
3eef9d0d 772 });
ec60b662
IC
773});
774},
775
88e2cdaa 776// Tabs show correct addresses when changed
cf7258fd
IC
777function() {
778page.open(url, function(status) {
779 // set the phrase
780 var expected = "17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz";
781 page.evaluate(function() {
782 $(".phrase").val("abandon abandon ability");
783 $(".phrase").trigger("input");
784 });
785 // change tabs
786 waitForGenerate(function() {
787 page.evaluate(function() {
788 $("#bip32-tab a").click();
789 });
790 // check the address is generated correctly
791 waitForGenerate(function() {
792 var actual = page.evaluate(function() {
793 return $(".address:first").text();
794 });
795 if (actual != expected) {
796 console.log("Clicking tab generates incorrect address");
797 console.log("Expected: " + expected);
798 console.log("Actual: " + actual);
799 fail();
800 }
801 next();
802 });
803 });
804});
805},
88e2cdaa
IC
806
807// BIP44 derivation path is shown
d077e1e7
IC
808function() {
809page.open(url, function(status) {
810 // set the phrase
811 var expected = "m/44'/0'/0'/0";
812 page.evaluate(function() {
813 $(".phrase").val("abandon abandon ability");
814 $(".phrase").trigger("input");
815 });
816 // check the derivation path of the first address
817 waitForGenerate(function() {
818 var actual = page.evaluate(function() {
819 return $("#bip44 .path").val();
820 });
821 if (actual != expected) {
822 console.log("BIP44 derivation path is incorrect");
823 console.log("Expected: " + expected);
824 console.log("Actual: " + actual);
825 fail();
826 }
827 next();
828 });
829});
830},
831
88e2cdaa 832// BIP44 extended private key is shown
4fd2925d
IC
833function() {
834page.open(url, function(status) {
835 // set the phrase
836 var expected = "xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG";
837 page.evaluate(function() {
838 $(".phrase").val("abandon abandon ability");
839 $(".phrase").trigger("input");
840 });
06286adb 841 // check the BIP44 extended private key
4fd2925d
IC
842 waitForGenerate(function() {
843 var actual = page.evaluate(function() {
844 return $(".extended-priv-key").val();
845 });
846 if (actual != expected) {
847 console.log("BIP44 extended private key is incorrect");
848 console.log("Expected: " + expected);
849 console.log("Actual: " + actual);
850 fail();
851 }
852 next();
853 });
854});
855},
856
88e2cdaa 857// BIP44 extended public key is shown
39fd45bb
IC
858function() {
859page.open(url, function(status) {
860 // set the phrase
861 var expected = "xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM";
862 page.evaluate(function() {
863 $(".phrase").val("abandon abandon ability");
864 $(".phrase").trigger("input");
865 });
06286adb 866 // check the BIP44 extended public key
39fd45bb
IC
867 waitForGenerate(function() {
868 var actual = page.evaluate(function() {
869 return $(".extended-pub-key").val();
870 });
871 if (actual != expected) {
872 console.log("BIP44 extended public key is incorrect");
873 console.log("Expected: " + expected);
874 console.log("Actual: " + actual);
875 fail();
876 }
877 next();
878 });
879});
880},
881
06286adb
IC
882// BIP44 purpose field changes address list
883function() {
884page.open(url, function(status) {
885 // set the phrase
886 var expected = "1JbDzRJ2cDT8aat2xwKd6Pb2zzavow5MhF";
887 page.evaluate(function() {
888 $(".phrase").val("abandon abandon ability");
889 $(".phrase").trigger("input");
890 });
891 waitForGenerate(function() {
892 // change the bip44 purpose field to 45
893 page.evaluate(function() {
894 $("#bip44 .purpose").val("45");
895 $("#bip44 .purpose").trigger("input");
896 });
897 waitForGenerate(function() {
898 // check the address for the new derivation path
899 var actual = page.evaluate(function() {
900 return $(".address:first").text();
901 });
902 if (actual != expected) {
903 console.log("BIP44 purpose field generates incorrect address");
904 console.log("Expected: " + expected);
905 console.log("Actual: " + actual);
906 fail();
907 }
908 next();
909 });
910 });
911});
912},
913
88e2cdaa 914// BIP44 coin field changes address list
9eb72cdf
IC
915function() {
916page.open(url, function(status) {
917 // set the phrase
918 var expected = "1F6dB2djQYrxoyfZZmfr6D5voH8GkJTghk";
919 page.evaluate(function() {
920 $(".phrase").val("abandon abandon ability");
921 $(".phrase").trigger("input");
922 });
923 waitForGenerate(function() {
924 // change the bip44 purpose field to 45
925 page.evaluate(function() {
926 $("#bip44 .coin").val("1");
927 $("#bip44 .coin").trigger("input");
928 });
929 waitForGenerate(function() {
930 // check the address for the new derivation path
931 var actual = page.evaluate(function() {
932 return $(".address:first").text();
933 });
934 if (actual != expected) {
935 console.log("BIP44 coin field generates incorrect address");
936 console.log("Expected: " + expected);
937 console.log("Actual: " + actual);
938 fail();
939 }
940 next();
941 });
942 });
943});
944},
945
88e2cdaa 946// BIP44 account field changes address list
048bc3e0
IC
947function() {
948page.open(url, function(status) {
949 // set the phrase
950 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
951 page.evaluate(function() {
952 $(".phrase").val("abandon abandon ability");
953 $(".phrase").trigger("input");
954 });
955 waitForGenerate(function() {
956 // change the bip44 purpose field to 45
957 page.evaluate(function() {
958 $("#bip44 .account").val("1");
959 $("#bip44 .account").trigger("input");
960 });
961 waitForGenerate(function() {
962 // check the address for the new derivation path
963 var actual = page.evaluate(function() {
964 return $(".address:first").text();
965 });
966 if (actual != expected) {
967 console.log("BIP44 account field generates incorrect address");
968 console.log("Expected: " + expected);
969 console.log("Actual: " + actual);
970 fail();
971 }
972 next();
973 });
974 });
975});
976},
977
fa4da086
IC
978// BIP44 change field changes address list
979function() {
980page.open(url, function(status) {
981 // set the phrase
982 var expected = "1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo";
983 page.evaluate(function() {
984 $(".phrase").val("abandon abandon ability");
985 $(".phrase").trigger("input");
986 });
987 waitForGenerate(function() {
988 // change the bip44 purpose field to 45
989 page.evaluate(function() {
990 $("#bip44 .change").val("1");
991 $("#bip44 .change").trigger("input");
992 });
993 waitForGenerate(function() {
994 // check the address for the new derivation path
995 var actual = page.evaluate(function() {
996 return $(".address:first").text();
997 });
998 if (actual != expected) {
999 console.log("BIP44 change field generates incorrect address");
1000 console.log("Expected: " + expected);
1001 console.log("Actual: " + actual);
1002 fail();
1003 }
1004 next();
1005 });
1006 });
1007});
1008},
048bc3e0 1009
88e2cdaa 1010// BIP32 derivation path can be set
651382a3
IC
1011function() {
1012page.open(url, function(status) {
1013 // set the phrase
1014 var expected = "16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L";
1015 page.evaluate(function() {
1016 $(".phrase").val("abandon abandon ability");
1017 $(".phrase").trigger("input");
1018 });
1019 // change tabs
1020 waitForGenerate(function() {
1021 page.evaluate(function() {
1022 $("#bip32-tab a").click();
1023 });
1024 // set the derivation path to m/1
1025 waitForGenerate(function() {
1026 page.evaluate(function() {
1027 $("#bip32 .path").val("m/1");
1028 $("#bip32 .path").trigger("input");
1029 });
1030 // check the address is generated correctly
1031 waitForGenerate(function() {
1032 var actual = page.evaluate(function() {
1033 return $(".address:first").text();
1034 });
1035 if (actual != expected) {
1036 console.log("Custom BIP32 path generates incorrect address");
1037 console.log("Expected: " + expected);
1038 console.log("Actual: " + actual);
1039 fail();
1040 }
1041 next();
1042 });
1043 });
1044 });
1045});
1046},
1047
88e2cdaa 1048// BIP32 can use hardened derivation paths
651382a3
IC
1049function() {
1050page.open(url, function(status) {
1051 // set the phrase
1052 var expected = "14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4";
1053 page.evaluate(function() {
1054 $(".phrase").val("abandon abandon ability");
1055 $(".phrase").trigger("input");
1056 });
1057 // change tabs
1058 waitForGenerate(function() {
1059 page.evaluate(function() {
1060 $("#bip32-tab a").click();
1061 });
1062 // set the derivation path to m/0'
1063 waitForGenerate(function() {
1064 page.evaluate(function() {
1065 $("#bip32 .path").val("m/0'");
1066 $("#bip32 .path").trigger("input");
1067 });
1068 // check the address is generated correctly
1069 waitForGenerate(function() {
1070 var actual = page.evaluate(function() {
1071 return $(".address:first").text();
1072 });
1073 if (actual != expected) {
1074 console.log("Hardened BIP32 path generates incorrect address");
1075 console.log("Expected: " + expected);
1076 console.log("Actual: " + actual);
1077 fail();
1078 }
1079 next();
1080 });
1081 });
1082 });
1083});
1084},
1085
88e2cdaa 1086// BIP32 extended private key is shown
9e9dcfda
IC
1087function() {
1088page.open(url, function(status) {
1089 // set the phrase
1090 var expected = "xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe";
1091 page.evaluate(function() {
1092 $(".phrase").val("abandon abandon ability");
1093 $(".phrase").trigger("input");
1094 });
1095 // change tabs
1096 waitForGenerate(function() {
1097 page.evaluate(function() {
1098 $("#bip32-tab a").click();
1099 });
1100 // check the extended private key is generated correctly
1101 waitForGenerate(function() {
1102 var actual = page.evaluate(function() {
1103 return $(".extended-priv-key").val();
1104 });
1105 if (actual != expected) {
1106 console.log("BIP32 extended private key is incorrect");
1107 console.log("Expected: " + expected);
1108 console.log("Actual: " + actual);
1109 fail();
1110 }
1111 next();
1112 });
1113 });
1114});
1115},
1116
88e2cdaa 1117// BIP32 extended public key is shown
9e9dcfda
IC
1118function() {
1119page.open(url, function(status) {
1120 // set the phrase
1121 var expected = "xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P";
1122 page.evaluate(function() {
1123 $(".phrase").val("abandon abandon ability");
1124 $(".phrase").trigger("input");
1125 });
1126 // change tabs
1127 waitForGenerate(function() {
1128 page.evaluate(function() {
1129 $("#bip32-tab a").click();
1130 });
1131 // check the extended public key is generated correctly
1132 waitForGenerate(function() {
1133 var actual = page.evaluate(function() {
1134 return $(".extended-pub-key").val();
1135 });
1136 if (actual != expected) {
1137 console.log("BIP32 extended public key is incorrect");
1138 console.log("Expected: " + expected);
1139 console.log("Actual: " + actual);
1140 fail();
1141 }
1142 next();
1143 });
1144 });
1145});
1146},
88e2cdaa
IC
1147
1148// Derivation path is shown in table
5f844c62
IC
1149function() {
1150page.open(url, function(status) {
1151 // set the phrase
1152 var expected = "m/44'/0'/0'/0/0";
1153 page.evaluate(function() {
1154 $(".phrase").val("abandon abandon ability");
1155 $(".phrase").trigger("input");
1156 });
1157 // check for derivation path in table
1158 waitForGenerate(function() {
1159 var actual = page.evaluate(function() {
1160 return $(".index:first").text();
1161 });
1162 if (actual != expected) {
1163 console.log("Derivation path shown incorrectly in table");
1164 console.log("Expected: " + expected);
1165 console.log("Actual: " + actual);
1166 fail();
1167 }
1168 next();
1169 });
1170});
1171},
1172
88e2cdaa 1173// Derivation path for address can be hardened
4974fd7f
IC
1174function() {
1175page.open(url, function(status) {
1176 // set the phrase
1177 var expected = "18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd";
1178 page.evaluate(function() {
1179 $(".phrase").val("abandon abandon ability");
1180 $(".phrase").trigger("input");
1181 });
1182 // change tabs
1183 waitForGenerate(function() {
1184 page.evaluate(function() {
1185 $("#bip32-tab a").click();
1186 });
1187 waitForGenerate(function() {
1188 // select the hardened addresses option
1189 page.evaluate(function() {
1190 $(".hardened-addresses").prop("checked", true);
1191 $(".hardened-addresses").trigger("change");
1192 });
1193 waitForGenerate(function() {
1194 // check the generated address is hardened
1195 var actual = page.evaluate(function() {
1196 return $(".address:first").text();
1197 });
1198 if (actual != expected) {
1199 console.log("Hardened address is incorrect");
1200 console.log("Expected: " + expected);
1201 console.log("Actual: " + actual);
1202 fail();
1203 }
1204 next();
1205 });
1206 });
1207 });
1208});
1209},
1210
88e2cdaa 1211// Derivation path visibility can be toggled
a775b5c6
IC
1212function() {
1213page.open(url, function(status) {
1214 // set the phrase
1215 page.evaluate(function() {
1216 $(".phrase").val("abandon abandon ability");
1217 $(".phrase").trigger("input");
1218 });
a775b5c6
IC
1219 waitForGenerate(function() {
1220 // toggle path visibility
1221 page.evaluate(function() {
1222 $(".index-toggle").click();
1223 });
1224 // check the path is not visible
1225 var isInvisible = page.evaluate(function() {
1226 return $(".index:first span").hasClass("invisible");
1227 });
1228 if (!isInvisible) {
1229 console.log("Toggled derivation path is visible");
1230 fail();
1231 }
1232 next();
1233 });
1234});
1235},
1236
88e2cdaa 1237// Address is shown
06c4c6e3
IC
1238function() {
1239page.open(url, function(status) {
1240 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1241 // set the phrase
1242 page.evaluate(function() {
1243 $(".phrase").val("abandon abandon ability").trigger("input");
1244 });
1245 // get the address
1246 waitForGenerate(function() {
1247 var actual = page.evaluate(function() {
1248 return $(".address:first").text();
1249 });
1250 if (actual != expected) {
1251 console.log("Address is not shown");
1252 console.log("Expected: " + expected);
1253 console.log("Got: " + actual);
1254 fail();
1255 }
1256 next();
1257 });
1258});
1259},
1260
88e2cdaa 1261// Addresses are shown in order of derivation path
3f1faa4d
IC
1262function() {
1263page.open(url, function(status) {
1264 // set the phrase
1265 page.evaluate(function() {
1266 $(".phrase").val("abandon abandon ability").trigger("input");
1267 });
1268 // get the derivation paths
1269 waitForGenerate(function() {
1270 var paths = page.evaluate(function() {
1271 return $(".index").map(function(i, e) {
1272 return $(e).text();
1273 });
1274 });
1275 if (paths.length != 20) {
1276 console.log("Total paths is less than expected: " + paths.length);
1277 fail();
1278 }
1279 for (var i=0; i<paths.length; i++) {
1280 var expected = "m/44'/0'/0'/0/" + i;
1281 var actual = paths[i];
1282 if (actual != expected) {
1283 console.log("Path " + i + " is incorrect");
1284 console.log("Expected: " + expected);
1285 console.log("Actual: " + actual);
1286 fail();
1287 }
1288 }
1289 next();
1290 });
1291});
1292},
21372fab 1293
88e2cdaa 1294// Address visibility can be toggled
21372fab
IC
1295function() {
1296page.open(url, function(status) {
1297 // set the phrase
1298 page.evaluate(function() {
1299 $(".phrase").val("abandon abandon ability");
1300 $(".phrase").trigger("input");
1301 });
1302 waitForGenerate(function() {
1303 // toggle address visibility
1304 page.evaluate(function() {
1305 $(".address-toggle").click();
1306 });
1307 // check the address is not visible
1308 var isInvisible = page.evaluate(function() {
1309 return $(".address:first span").hasClass("invisible");
1310 });
1311 if (!isInvisible) {
1312 console.log("Toggled address is visible");
1313 fail();
1314 }
1315 next();
1316 });
1317});
1318},
1319
1b12b2f5
IC
1320// Public key is shown
1321function() {
1322page.open(url, function(status) {
1323 var expected = "033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3";
1324 // set the phrase
1325 page.evaluate(function() {
1326 $(".phrase").val("abandon abandon ability").trigger("input");
1327 });
1328 // get the address
1329 waitForGenerate(function() {
1330 var actual = page.evaluate(function() {
1331 return $(".pubkey:first").text();
1332 });
1333 if (actual != expected) {
1334 console.log("Public key is not shown");
1335 console.log("Expected: " + expected);
1336 console.log("Got: " + actual);
1337 fail();
1338 }
1339 next();
1340 });
1341});
1342},
1343
1344// Public key visibility can be toggled
1345function() {
1346page.open(url, function(status) {
1347 // set the phrase
1348 page.evaluate(function() {
1349 $(".phrase").val("abandon abandon ability");
1350 $(".phrase").trigger("input");
1351 });
1352 waitForGenerate(function() {
1353 // toggle public key visibility
1354 page.evaluate(function() {
1355 $(".public-key-toggle").click();
1356 });
1357 // check the public key is not visible
1358 var isInvisible = page.evaluate(function() {
1359 return $(".pubkey:first span").hasClass("invisible");
1360 });
1361 if (!isInvisible) {
1362 console.log("Toggled public key is visible");
1363 fail();
1364 }
1365 next();
1366 });
1367});
1368},
1369
88e2cdaa 1370// Private key is shown
8cd5e231
IC
1371function() {
1372page.open(url, function(status) {
1373 var expected = "L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE";
1374 // set the phrase
1375 page.evaluate(function() {
1376 $(".phrase").val("abandon abandon ability").trigger("input");
1377 });
1378 // get the address
1379 waitForGenerate(function() {
1380 var actual = page.evaluate(function() {
1381 return $(".privkey:first").text();
1382 });
1383 if (actual != expected) {
1384 console.log("Private key is not shown");
1385 console.log("Expected: " + expected);
1386 console.log("Got: " + actual);
1387 fail();
1388 }
1389 next();
1390 });
1391});
1392},
1393
88e2cdaa 1394// Private key visibility can be toggled
6848d03b
IC
1395function() {
1396page.open(url, function(status) {
1397 // set the phrase
1398 page.evaluate(function() {
1399 $(".phrase").val("abandon abandon ability");
1400 $(".phrase").trigger("input");
1401 });
1402 waitForGenerate(function() {
1403 // toggle private key visibility
1404 page.evaluate(function() {
1405 $(".private-key-toggle").click();
1406 });
1407 // check the private key is not visible
1408 var isInvisible = page.evaluate(function() {
1409 return $(".privkey:first span").hasClass("invisible");
1410 });
1411 if (!isInvisible) {
1412 console.log("Toggled private key is visible");
1413 fail();
1414 }
1415 next();
1416 });
1417});
1418},
88e2cdaa
IC
1419
1420// More addresses can be generated
35631659
IC
1421function() {
1422page.open(url, function(status) {
1423 // set the phrase
1424 page.evaluate(function() {
1425 $(".phrase").val("abandon abandon ability");
1426 $(".phrase").trigger("input");
1427 });
1428 waitForGenerate(function() {
1429 // generate more addresses
1430 page.evaluate(function() {
1431 $(".more").click();
1432 });
1433 waitForGenerate(function() {
1434 // check there are more addresses
1435 var addressCount = page.evaluate(function() {
1436 return $(".address").length;
1437 });
1438 if (addressCount != 40) {
1439 console.log("More addresses cannot be generated");
1440 fail();
1441 }
1442 next();
1443 });
1444 });
1445});
1446},
1447
88e2cdaa 1448// A custom number of additional addresses can be generated
8a89b9da
IC
1449function() {
1450page.open(url, function(status) {
1451 // set the phrase
1452 page.evaluate(function() {
1453 $(".phrase").val("abandon abandon ability");
1454 $(".phrase").trigger("input");
1455 });
1456 waitForGenerate(function() {
1457 // get the current number of addresses
1458 var oldAddressCount = page.evaluate(function() {
1459 return $(".address").length;
1460 });
1461 // set a custom number of additional addresses
1462 page.evaluate(function() {
1463 $(".rows-to-add").val(1);
1464 });
1465 // generate more addresses
1466 page.evaluate(function() {
1467 $(".more").click();
1468 });
1469 waitForGenerate(function() {
1470 // check there are the correct number of addresses
1471 var newAddressCount = page.evaluate(function() {
1472 return $(".address").length;
1473 });
1474 if (newAddressCount - oldAddressCount != 1) {
1475 console.log("Number of additional addresses cannot be customized");
1476 console.log(newAddressCount)
1477 console.log(oldAddressCount)
1478 fail();
1479 }
1480 next();
1481 });
1482 });
1483});
1484},
1485
88e2cdaa 1486// Additional addresses are shown in order of derivation path
4d387bf5
IC
1487function() {
1488page.open(url, function(status) {
1489 // set the phrase
1490 page.evaluate(function() {
1491 $(".phrase").val("abandon abandon ability").trigger("input");
1492 });
1493 waitForGenerate(function() {
1494 // generate more addresses
1495 page.evaluate(function() {
1496 $(".more").click();
1497 });
1498 // get the derivation paths
1499 waitForGenerate(function() {
1500 var paths = page.evaluate(function() {
1501 return $(".index").map(function(i, e) {
1502 return $(e).text();
1503 });
1504 });
1505 if (paths.length != 40) {
1506 console.log("Total additional paths is less than expected: " + paths.length);
1507 fail();
1508 }
1509 for (var i=0; i<paths.length; i++) {
1510 var expected = "m/44'/0'/0'/0/" + i;
1511 var actual = paths[i];
1512 if (actual != expected) {
1513 console.log("Path " + i + " is not in correct order");
1514 console.log("Expected: " + expected);
1515 console.log("Actual: " + actual);
1516 fail();
1517 }
1518 }
1519 next();
1520 });
1521 });
1522});
1523},
88e2cdaa
IC
1524
1525// BIP32 root key can be set by the user
61ed16a9
IC
1526function() {
1527page.open(url, function(status) {
1528 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1529 // set the root key
1530 page.evaluate(function() {
1531 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1532 });
1533 waitForGenerate(function() {
1534 var actual = page.evaluate(function() {
1535 return $(".address:first").text();
1536 });
1537 if (actual != expected) {
bc324fd2 1538 console.log("Setting BIP32 root key results in wrong address");
61ed16a9
IC
1539 console.log("Expected: " + expected);
1540 console.log("Actual: " + actual);
1541 fail();
1542 }
1543 next();
1544 });
1545});
1546},
1547
54563907 1548// Setting BIP32 root key clears the existing phrase, passphrase and seed
bc324fd2
IC
1549function() {
1550page.open(url, function(status) {
1551 var expected = "";
1552 // set a mnemonic
1553 page.evaluate(function() {
1554 $(".phrase").val("A non-blank but invalid value");
1555 });
1556 // Accept any confirm dialogs
1557 page.onConfirm = function() {
1558 return true;
1559 };
1560 // set the root key
1561 page.evaluate(function() {
1562 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1563 });
1564 waitForGenerate(function() {
1565 var actual = page.evaluate(function() {
1566 return $(".phrase").val();
1567 });
1568 if (actual != expected) {
1569 console.log("Phrase not cleared when setting BIP32 root key");
1570 console.log("Expected: " + expected);
1571 console.log("Actual: " + actual);
1572 fail();
1573 }
1574 next();
1575 });
1576});
1577},
1578
54563907 1579// Clearing of phrase, passphrase and seed can be cancelled by user
abfbe450
IC
1580function() {
1581page.open(url, function(status) {
1582 var expected = "abandon abandon ability";
1583 // set a mnemonic
1584 page.evaluate(function() {
1585 $(".phrase").val("abandon abandon ability");
1586 });
1587 // Cancel any confirm dialogs
1588 page.onConfirm = function() {
1589 return false;
1590 };
1591 // set the root key
1592 page.evaluate(function() {
1593 $(".root-key").val("xprv9s21ZrQH143K3d3vzEDD3KpSKmxsZ3y7CqhAL1tinwtP6wqK4TKEKjpBuo6P2hUhB6ZENo7TTSRytiP857hBZVpBdk8PooFuRspE1eywwNZ").trigger("input");
1594 });
1595 var actual = page.evaluate(function() {
1596 return $(".phrase").val();
1597 });
1598 if (actual != expected) {
1599 console.log("Phrase not retained when cancelling changes to BIP32 root key");
1600 console.log("Expected: " + expected);
1601 console.log("Actual: " + actual);
1602 fail();
1603 }
1604 next();
1605});
1606},
7ff86d4c 1607
88e2cdaa 1608// Custom BIP32 root key is used when changing the derivation path
7ff86d4c
IC
1609function() {
1610page.open(url, function(status) {
1611 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
1612 // set the root key
1613 page.evaluate(function() {
1614 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1615 });
1616 waitForGenerate(function() {
1617 // change the derivation path
1618 page.evaluate(function() {
1619 $("#account").val("1").trigger("input");
1620 });
1621 // check the bip32 root key is used for derivation, not the blank phrase
1622 waitForGenerate(function() {
1623 var actual = page.evaluate(function() {
1624 return $(".address:first").text();
1625 });
1626 if (actual != expected) {
1627 console.log("Changing the derivation path does not use BIP32 root key");
1628 console.log("Expected: " + expected);
1629 console.log("Actual: " + actual);
1630 fail();
1631 }
1632 next();
1633 });
1634 });
1635});
1636},
88e2cdaa
IC
1637
1638// Incorrect mnemonic shows error
c3719b00
IC
1639function() {
1640page.open(url, function(status) {
1641 // set the root key
1642 page.evaluate(function() {
1643 $(".phrase").val("abandon abandon abandon").trigger("input");
1644 });
1645 waitForFeedback(function() {
1646 // check there is an error shown
1647 var feedback = page.evaluate(function() {
1648 return $(".feedback").text();
1649 });
1650 if (feedback.length <= 0) {
1651 console.log("Invalid mnemonic does not show error");
1652 fail();
1653 }
1654 next();
1655 });
1656});
1657},
1658
88e2cdaa 1659// Incorrect word shows suggested replacement
20f80cfa
IC
1660function() {
1661page.open(url, function(status) {
1662 // set the root key
1663 page.evaluate(function() {
1664 $(".phrase").val("abandon abandon abiliti").trigger("input");
1665 });
1666 // check there is a suggestion shown
1667 waitForFeedback(function() {
1668 var feedback = page.evaluate(function() {
1669 return $(".feedback").text();
1670 });
1671 if (feedback.indexOf("did you mean ability?") < 0) {
1672 console.log("Incorrect word does not show suggested replacement");
1673 console.log("Error: " + error);
1674 fail();
6ea15134
IC
1675 }
1676 next();
1677 });
1678});
1679},
1680
1681// Github pull request 48
1682// First four letters of word shows that word, not closest
1683// since first four letters gives unique word in BIP39 wordlist
1684// eg ille should show illegal, not idle
1685function() {
1686page.open(url, function(status) {
1687 // set the incomplete word
1688 page.evaluate(function() {
1689 $(".phrase").val("ille").trigger("input");
1690 });
1691 // check there is a suggestion shown
1692 waitForFeedback(function() {
1693 var feedback = page.evaluate(function() {
1694 return $(".feedback").text();
1695 });
1696 if (feedback.indexOf("did you mean illegal?") < 0) {
1697 console.log("Start of word does not show correct suggestion");
1698 console.log("Error: " + error);
1699 fail();
20f80cfa
IC
1700 }
1701 next();
1702 });
1703});
1704},
1705
88e2cdaa 1706// Incorrect BIP32 root key shows error
02f4a90e
IC
1707function() {
1708page.open(url, function(status) {
1709 // set the root key
1710 page.evaluate(function() {
1711 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj").trigger("input");
1712 });
1713 // check there is an error shown
1714 waitForFeedback(function() {
1715 var feedback = page.evaluate(function() {
1716 return $(".feedback").text();
1717 });
1718 if (feedback != "Invalid root key") {
1719 console.log("Invalid root key does not show error");
1720 console.log("Error: " + error);
1721 fail();
1722 }
1723 next();
1724 });
1725});
1726},
1727
88e2cdaa 1728// Derivation path not starting with m shows error
f976b541
IC
1729function() {
1730page.open(url, function(status) {
1731 // set the mnemonic phrase
1732 page.evaluate(function() {
1733 $(".phrase").val("abandon abandon ability").trigger("input");
1734 });
1735 waitForGenerate(function() {
1736 // select the bip32 tab so custom derivation path can be set
1737 page.evaluate(function() {
1738 $("#bip32-tab a").click();
1739 });
1740 waitForGenerate(function() {
1741 // set the incorrect derivation path
1742 page.evaluate(function() {
1743 $("#bip32 .path").val("n/0").trigger("input");
1744 });
1745 waitForFeedback(function() {
1746 var feedback = page.evaluate(function() {
1747 return $(".feedback").text();
1748 });
1749 if (feedback != "First character must be 'm'") {
1750 console.log("Derivation path not starting with m should show error");
1751 console.log("Error: " + error);
1752 fail();
1753 }
1754 next();
1755 });
1756 });
1757 });
1758});
1759},
1760
88e2cdaa 1761// Derivation path containing invalid characters shows useful error
55c0ffcb
IC
1762function() {
1763page.open(url, function(status) {
1764 // set the mnemonic phrase
1765 page.evaluate(function() {
1766 $(".phrase").val("abandon abandon ability").trigger("input");
1767 });
1768 waitForGenerate(function() {
1769 // select the bip32 tab so custom derivation path can be set
1770 page.evaluate(function() {
1771 $("#bip32-tab a").click();
1772 });
1773 waitForGenerate(function() {
1774 // set the incorrect derivation path
1775 page.evaluate(function() {
1776 $("#bip32 .path").val("m/1/0wrong1/1").trigger("input");
1777 });
1778 waitForFeedback(function() {
1779 var feedback = page.evaluate(function() {
1780 return $(".feedback").text();
1781 });
1782 if (feedback != "Invalid characters 0wrong1 found at depth 2") {
1783 console.log("Derivation path with invalid characters should show error");
1784 console.log("Error: " + error);
1785 fail();
1786 }
1787 next();
1788 });
1789 });
1790 });
1791});
1792},
88e2cdaa
IC
1793
1794// Github Issue 11: Default word length is 15
b630f83d 1795// https://github.com/iancoleman/bip39/issues/11
ca976aa9
IC
1796function() {
1797page.open(url, function(status) {
1798 // get the word length
1799 var defaultLength = page.evaluate(function() {
1800 return $(".strength").val();
1801 });
1802 if (defaultLength != 15) {
1803 console.log("Default word length is not 15");
1804 fail();
1805 }
1806 next();
1807});
1808},
1809
88e2cdaa
IC
1810
1811// Github Issue 12: Generate more rows with private keys hidden
b630f83d 1812// https://github.com/iancoleman/bip39/issues/12
c97627fa
IC
1813function() {
1814page.open(url, function(status) {
1815 // set the phrase
1816 page.evaluate(function() {
1817 $(".phrase").val("abandon abandon ability");
1818 $(".phrase").trigger("input");
1819 });
1820 waitForGenerate(function() {
1821 // toggle private keys hidden, then generate more addresses
1822 page.evaluate(function() {
1823 $(".private-key-toggle").click();
1824 $(".more").click();
1825 });
1826 waitForGenerate(function() {
1827 // check more have been generated
1828 var expected = 40;
1829 var numPrivKeys = page.evaluate(function() {
1830 return $(".privkey").length;
1831 });
1832 if (numPrivKeys != expected) {
1833 console.log("Wrong number of addresses when clicking 'more' with hidden privkeys");
1834 console.log("Expected: " + expected);
1835 console.log("Actual: " + numPrivKeys);
1836 fail();
1837 }
1838 // check no private keys are shown
1839 var numHiddenPrivKeys = page.evaluate(function() {
1840 return $(".privkey span[class=invisible]").length;
1841 });
1842 if (numHiddenPrivKeys != expected) {
1843 console.log("Generating more does not retain hidden state of privkeys");
1844 console.log("Expected: " + expected);
1845 console.log("Actual: " + numHiddenPrivKeys);
1846 fail();
1847 }
1848 next();
1849 });
1850 });
1851});
1852},
88e2cdaa
IC
1853
1854// Github Issue 19: Mnemonic is not sensitive to whitespace
b630f83d 1855// https://github.com/iancoleman/bip39/issues/19
a7becc43
IC
1856function() {
1857page.open(url, function(status) {
1858 // set the phrase
1859 var expected = "xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC";
1860 page.evaluate(function() {
1861 var doubleSpace = " ";
1862 $(".phrase").val("urge cat" + doubleSpace + "bid");
1863 $(".phrase").trigger("input");
1864 });
1865 waitForGenerate(function() {
1866 // Check the bip32 root key is correct
1867 var actual = page.evaluate(function() {
1868 return $(".root-key").val();
1869 });
1870 if (actual != expected) {
1871 console.log("Mnemonic is sensitive to whitespace");
1872 console.log("Expected: " + expected);
1873 console.log("Actual: " + actual);
1874 fail();
1875 }
1876 next();
1877 });
1878});
1879},
88e2cdaa 1880
e3001539 1881// Github Issue 23: Part 1: Use correct derivation path when changing tabs
b630f83d 1882// https://github.com/iancoleman/bip39/issues/23
e3001539
IC
1883function() {
1884page.open(url, function(status) {
1885 // 1) and 2) set the phrase
1886 page.evaluate(function() {
1887 $(".phrase").val("abandon abandon ability").trigger("input");
1888 });
1889 waitForGenerate(function() {
1890 // 3) select bip32 tab
1891 page.evaluate(function() {
1892 $("#bip32-tab a").click();
1893 });
1894 waitForGenerate(function() {
1895 // 4) switch from bitcoin to litecoin
1896 page.evaluate(function() {
52d589ea
IC
1897 $(".network option").filter(function() {
1898 return $(this).html() == "Litecoin";
1899 }).prop("selected", true);
1900 $(".network").trigger("change");
e3001539
IC
1901 });
1902 waitForGenerate(function() {
1903 // 5) Check derivation path is displayed correctly
1904 var expected = "m/0/0";
1905 var actual = page.evaluate(function() {
1906 return $(".index:first").text();
1907 });
1908 if (actual != expected) {
1909 console.log("Github Issue 23 Part 1: derivation path display error");
1910 console.log("Expected: " + expected);
1911 console.log("Actual: " + actual);
1912 fail();
1913 }
1914 // 5) Check address is displayed correctly
1915 var expected = "LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5";
1916 var actual = page.evaluate(function() {
1917 return $(".address:first").text();
1918 });
1919 if (actual != expected) {
1920 console.log("Github Issue 23 Part 1: address display error");
1921 console.log("Expected: " + expected);
1922 console.log("Actual: " + actual);
1923 fail();
1924 }
1925 next();
1926 });
1927 });
1928 });
1929});
1930},
1931
1932// Github Issue 23 Part 2: Coin selection in derivation path
b630f83d 1933// https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920
af4fd3a2
IC
1934function() {
1935page.open(url, function(status) {
1936 // set the phrase
1937 page.evaluate(function() {
1938 $(".phrase").val("abandon abandon ability").trigger("input");
1939 });
1940 waitForGenerate(function() {
1941 // switch from bitcoin to clam
1942 page.evaluate(function() {
52d589ea
IC
1943 $(".network option").filter(function() {
1944 return $(this).html() == "CLAM";
1945 }).prop("selected", true);
1946 $(".network").trigger("change");
af4fd3a2
IC
1947 });
1948 waitForGenerate(function() {
1949 // check derivation path is displayed correctly
1950 var expected = "m/44'/23'/0'/0/0";
1951 var actual = page.evaluate(function() {
1952 return $(".index:first").text();
1953 });
1954 if (actual != expected) {
1955 console.log("Github Issue 23 Part 2: Coin in BIP44 derivation path is incorrect");
1956 console.log("Expected: " + expected);
1957 console.log("Actual: " + actual);
1958 fail();
1959 }
1960 next();
1961 });
1962 });
1963});
1964},
88e2cdaa 1965
f3d0aca1 1966// Github Issue 26: When using a Root key derrived altcoins are incorrect
b630f83d 1967// https://github.com/iancoleman/bip39/issues/26
558ef9ac
IC
1968function() {
1969page.open(url, function(status) {
1970 // 1) 2) and 3) set the root key
1971 page.evaluate(function() {
1972 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1973 });
1974 waitForGenerate(function() {
1975 // 4) switch from bitcoin to viacoin
1976 page.evaluate(function() {
52d589ea
IC
1977 $(".network option").filter(function() {
1978 return $(this).html() == "Viacoin";
1979 }).prop("selected", true);
1980 $(".network").trigger("change");
558ef9ac
IC
1981 });
1982 waitForGenerate(function() {
1983 // 5) ensure the derived address is correct
1984 var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
1985 var actual = page.evaluate(function() {
1986 return $(".address:first").text();
1987 });
1988 if (actual != expected) {
1989 console.log("Github Issue 26: address is incorrect when changing networks and using root-key to derive");
1990 console.log("Expected: " + expected);
1991 console.log("Actual: " + actual);
1992 fail();
1993 }
1994 next();
1995 });
1996 });
1997});
1998},
f3d0aca1 1999
e1bae843
IC
2000// Selecting a language with no existing phrase should generate a phrase in
2001// that language.
2002function() {
2003page.open(url, function(status) {
2004 // Select a language
2005 // Need to manually simulate hash being set due to quirk between
2006 // 'click' event triggered by javascript vs triggered by mouse.
2007 // Perhaps look into page.sendEvent
2008 // http://phantomjs.org/api/webpage/method/send-event.html
2009 page.evaluate(function() {
2010 window.location.hash = "#japanese";
2011 $("a[href='#japanese']").trigger("click");
2012 });
2013 waitForGenerate(function() {
2014 // Check the mnemonic is in Japanese
2015 var phrase = page.evaluate(function() {
2016 return $(".phrase").val();
2017 });
2018 if (phrase.length <= 0) {
2019 console.log("No Japanese phrase generated");
2020 fail();
2021 }
2022 if (phrase.charCodeAt(0) < 128) {
2023 console.log("First character of Japanese phrase is ascii");
2024 console.log("Phrase: " + phrase);
2025 fail();
2026 }
2027 next();
2028 });
2029});
2030},
2031
2032// Selecting a language with existing phrase should update the phrase to use
2033// that language.
2034function() {
2035page.open(url, function(status) {
2036 // Set the phrase to an English phrase.
2037 page.evaluate(function() {
2038 $(".phrase").val("abandon abandon ability").trigger("input");
2039 });
2040 waitForGenerate(function() {
2041 // Change to Italian
2042 // Need to manually simulate hash being set due to quirk between
2043 // 'click' event triggered by javascript vs triggered by mouse.
2044 // Perhaps look into page.sendEvent
2045 // http://phantomjs.org/api/webpage/method/send-event.html
2046 page.evaluate(function() {
2047 window.location.hash = "#italian";
2048 $("a[href='#italian']").trigger("click");
2049 });
2050 waitForGenerate(function() {
2051 // Check only the language changes, not the phrase
2052 var expected = "abaco abaco abbaglio";
2053 var actual = page.evaluate(function() {
2054 return $(".phrase").val();
2055 });
2056 if (actual != expected) {
2057 console.log("Changing language with existing phrase");
2058 console.log("Expected: " + expected);
2059 console.log("Actual: " + actual);
2060 fail();
2061 }
2062 // Check the address is correct
2063 var expected = "1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV";
2064 var actual = page.evaluate(function() {
2065 return $(".address:first").text();
2066 });
2067 if (actual != expected) {
2068 console.log("Changing language generates incorrect address");
2069 console.log("Expected: " + expected);
2070 console.log("Actual: " + actual);
2071 fail();
2072 }
2073 next();
2074 });
2075 });
2076});
2077},
2078
2079// Suggested replacement for erroneous word in non-English language
2080function() {
2081page.open(url, function(status) {
2082 // Set an incorrect phrase in Italian
2083 page.evaluate(function() {
2084 $(".phrase").val("abaco abaco zbbaglio").trigger("input");
2085 });
2086 waitForFeedback(function() {
2087 // Check the suggestion is correct
2088 var feedback = page.evaluate(function() {
2089 return $(".feedback").text();
2090 });
2091 if (feedback.indexOf("did you mean abbaglio?") < 0) {
2092 console.log("Incorrect Italian word does not show suggested replacement");
2093 console.log("Error: " + error);
2094 fail();
2095 }
2096 next();
2097 });
2098});
2099},
2100
2101
2102// Japanese word does not break across lines.
2103// Point 2 from
2104// https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
2105function() {
2106page.open(url, function(status) {
2107 hasWordBreakCss = page.content.indexOf("word-break: keep-all;") > -1;
2108 if (!hasWordBreakCss) {
2109 console.log("Japanese words can break across lines mid-word");
2110 console.log("Check CSS for '.phrase { word-break: keep-all; }'");
2111 fail();
2112 }
2113 // Run the next test
2114 next();
2115});
2116},
2117
2118// Language can be specified at page load using hash value in url
2119function() {
2120page.open(url, function(status) {
2121 // Set the page hash as if it were on a fresh page load
2122 page.evaluate(function() {
2123 window.location.hash = "#japanese";
2124 });
2125 // Generate a random phrase
2126 page.evaluate(function() {
2127 $(".generate").trigger("click");
2128 });
2129 waitForGenerate(function() {
2130 // Check the phrase is in Japanese
2131 var phrase = page.evaluate(function() {
2132 return $(".phrase").val();
2133 });
2134 if (phrase.length <= 0) {
2135 console.log("No phrase generated using url hash");
2136 fail();
2137 }
2138 if (phrase.charCodeAt(0) < 128) {
2139 console.log("Language not detected from url hash on page load.");
2140 console.log("Phrase: " + phrase);
2141 fail();
2142 }
2143 next();
2144 });
2145});
2146},
2147
c6624d51
IC
2148// Entropy unit tests
2149function() {
2150page.open(url, function(status) {
adc8ce12 2151 var response = page.evaluate(function() {
c6624d51
IC
2152 var e;
2153 // binary entropy is detected
adc8ce12
IC
2154 try {
2155 e = Entropy.fromString("01010101");
2156 if (e.base.str != "binary") {
2157 return "Binary entropy not detected correctly";
2158 }
2159 }
2160 catch (e) {
2161 return e.message;
c6624d51
IC
2162 }
2163 // base6 entropy is detected
adc8ce12
IC
2164 try {
2165 e = Entropy.fromString("012345012345");
2166 if (e.base.str != "base 6") {
2167 return "base6 entropy not detected correctly";
2168 }
2169 }
2170 catch (e) {
2171 return e.message;
c6624d51
IC
2172 }
2173 // dice entropy is detected
adc8ce12
IC
2174 try {
2175 e = Entropy.fromString("123456123456");
2176 if (e.base.str != "base 6 (dice)") {
2177 return "dice entropy not detected correctly";
2178 }
2179 }
2180 catch (e) {
2181 return e.message;
c6624d51
IC
2182 }
2183 // base10 entropy is detected
adc8ce12
IC
2184 try {
2185 e = Entropy.fromString("0123456789");
2186 if (e.base.str != "base 10") {
2187 return "base10 entropy not detected correctly";
2188 }
2189 }
2190 catch (e) {
2191 return e.message;
c6624d51
IC
2192 }
2193 // hex entropy is detected
adc8ce12
IC
2194 try {
2195 e = Entropy.fromString("0123456789ABCDEF");
2196 if (e.base.str != "hexadecimal") {
2197 return "hexadecimal entropy not detected correctly";
2198 }
2199 }
2200 catch (e) {
2201 return e.message;
2202 }
2203 // card entropy is detected
2204 try {
2205 e = Entropy.fromString("AC4DTHKS");
2206 if (e.base.str != "card") {
2207 return "card entropy not detected correctly";
2208 }
2209 }
2210 catch (e) {
2211 return e.message;
c6624d51
IC
2212 }
2213 // entropy is case insensitive
adc8ce12
IC
2214 try {
2215 e = Entropy.fromString("aBcDeF");
2216 if (e.cleanStr != "aBcDeF") {
2217 return "Entropy should not be case sensitive";
2218 }
2219 }
2220 catch (e) {
2221 return e.message;
c6624d51
IC
2222 }
2223 // dice entropy is converted to base6
adc8ce12
IC
2224 try {
2225 e = Entropy.fromString("123456");
425b75a9 2226 if (e.cleanStr != "123450") {
adc8ce12
IC
2227 return "Dice entropy is not automatically converted to base6";
2228 }
2229 }
2230 catch (e) {
2231 return e.message;
c6624d51
IC
2232 }
2233 // dice entropy is preferred to base6 if ambiguous
adc8ce12
IC
2234 try {
2235 e = Entropy.fromString("12345");
2236 if (e.base.str != "base 6 (dice)") {
2237 return "dice not used as default over base 6";
2238 }
2239 }
2240 catch (e) {
2241 return e.message;
c6624d51
IC
2242 }
2243 // unused characters are ignored
adc8ce12
IC
2244 try {
2245 e = Entropy.fromString("fghijkl");
2246 if (e.cleanStr != "f") {
2247 return "additional characters are not ignored";
2248 }
2249 }
2250 catch (e) {
2251 return e.message;
c6624d51
IC
2252 }
2253 // the lowest base is used by default
2254 // 7 could be decimal or hexadecimal, but should be detected as decimal
adc8ce12
IC
2255 try {
2256 e = Entropy.fromString("7");
2257 if (e.base.str != "base 10") {
2258 return "lowest base is not used";
2259 }
c6624d51 2260 }
adc8ce12
IC
2261 catch (e) {
2262 return e.message;
c6624d51
IC
2263 }
2264 // Leading zeros are retained
adc8ce12
IC
2265 try {
2266 e = Entropy.fromString("000A");
2267 if (e.cleanStr != "000A") {
2268 return "Leading zeros are not retained";
2269 }
2270 }
2271 catch (e) {
2272 return e.message;
c6624d51
IC
2273 }
2274 // Leading zeros are correctly preserved for hex in binary string
adc8ce12
IC
2275 try {
2276 e = Entropy.fromString("2A");
2277 if (e.binaryStr != "00101010") {
2278 return "Hex leading zeros are not correct in binary";
2279 }
2280 }
2281 catch (e) {
2282 return e.message;
2283 }
1cf1bbaf
IC
2284 // Leading zeros for base 6 as binary string
2285 // 20 = 2 events at 2.58 bits per event = 5 bits
2286 // 20 in base 6 = 12 in base 10 = 1100 in base 2
2287 // so it needs 1 bit of padding to be the right bit length
adc8ce12 2288 try {
1cf1bbaf
IC
2289 e = Entropy.fromString("20");
2290 if (e.binaryStr != "01100") {
0d0f07f9
IC
2291 return "Base 6 as binary has leading zeros";
2292 }
2293 }
2294 catch (e) {
2295 return e.message;
2296 }
1cf1bbaf 2297 // Leading zeros for base 10 as binary string
0d0f07f9 2298 try {
1cf1bbaf
IC
2299 e = Entropy.fromString("17");
2300 if (e.binaryStr != "010001") {
0d0f07f9
IC
2301 return "Base 10 as binary has leading zeros";
2302 }
2303 }
2304 catch (e) {
2305 return e.message;
2306 }
87ad2c6e 2307 // Leading zeros for card entropy as binary string.
9d33c892 2308 // Card entropy is hashed so 2c does not necessarily produce leading zeros.
0d0f07f9 2309 try {
9d33c892
IC
2310 e = Entropy.fromString("2c");
2311 if (e.binaryStr != "0010") {
0d0f07f9 2312 return "Card entropy as binary has leading zeros";
adc8ce12
IC
2313 }
2314 }
2315 catch (e) {
2316 return e.message;
c6624d51
IC
2317 }
2318 // Keyboard mashing results in weak entropy
2319 // Despite being a long string, it's less than 30 bits of entropy
adc8ce12
IC
2320 try {
2321 e = Entropy.fromString("aj;se ifj; ask,dfv js;ifj");
2322 if (e.binaryStr.length >= 30) {
2323 return "Keyboard mashing should produce weak entropy";
2324 }
c6624d51 2325 }
adc8ce12
IC
2326 catch (e) {
2327 return e.message;
2328 }
2329 // Card entropy is used if every pair could be a card
2330 try {
2331 e = Entropy.fromString("4c3c2c");
2332 if (e.base.str != "card") {
2333 return "Card entropy not used if all pairs are cards";
2334 }
2335 }
2336 catch (e) {
2337 return e.message;
2338 }
2339 // Card entropy uses base 52
2340 // [ cards, binary ]
2341 try {
2342 var cards = [
9d33c892
IC
2343 [ "ac", "0101" ],
2344 [ "acqs", "11011100" ],
2345 [ "acks", "01011100" ],
2346 [ "2cac", "11111000" ],
2347 [ "2c", "0010" ],
2348 [ "3d", "0001" ],
2349 [ "4h", "1001" ],
87ad2c6e 2350 [ "5s", "1001" ],
9d33c892
IC
2351 [ "6c", "0000" ],
2352 [ "7d", "0001" ],
87ad2c6e 2353 [ "8h", "1011" ],
9d33c892
IC
2354 [ "9s", "0010" ],
2355 [ "tc", "1001" ],
2356 [ "jd", "1111" ],
2357 [ "qh", "0010" ],
2358 [ "ks", "0101" ],
2359 [ "ks2c", "01010100" ],
2360 [ "KS2C", "01010100" ],
adc8ce12
IC
2361 ];
2362 for (var i=0; i<cards.length; i++) {
2363 var card = cards[i][0];
2364 var result = cards[i][1];
2365 e = Entropy.fromString(card);
2366 console.log(e.binary + " " + result);
2367 if (e.binaryStr !== result) {
886f06ee 2368 return "card entropy " + card + " not parsed correctly: " + result + " != " + e.binaryStr;
adc8ce12
IC
2369 }
2370 }
2371 }
2372 catch (e) {
2373 return e.message;
2374 }
2375 return "PASS";
c6624d51 2376 });
adc8ce12 2377 if (response != "PASS") {
c6624d51 2378 console.log("Entropy unit tests");
adc8ce12 2379 console.log(response);
c6624d51
IC
2380 fail();
2381 };
2382 next();
2383});
2384},
2385
2386// Entropy can be entered by the user
2387function() {
2388page.open(url, function(status) {
2389 expected = {
2390 mnemonic: "abandon abandon ability",
2391 address: "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug",
2392 }
2393 // use entropy
2394 page.evaluate(function() {
2395 $(".use-entropy").prop("checked", true).trigger("change");
2396 $(".entropy").val("00000000 00000000 00000000 00000000").trigger("input");
2397 });
2398 // check the mnemonic is set and address is correct
2399 waitForGenerate(function() {
2400 var actual = page.evaluate(function() {
2401 return {
2402 address: $(".address:first").text(),
2403 mnemonic: $(".phrase").val(),
2404 }
2405 });
2406 if (actual.mnemonic != expected.mnemonic) {
2407 console.log("Entropy does not generate correct mnemonic");
2408 console.log("Expected: " + expected.mnemonic);
2409 console.log("Got: " + actual.mnemonic);
2410 fail();
2411 }
2412 if (actual.address != expected.address) {
2413 console.log("Entropy does not generate correct address");
2414 console.log("Expected: " + expected.address);
2415 console.log("Got: " + actual.address);
2416 fail();
2417 }
2418 next();
2419 });
2420});
2421},
2422
2423// A warning about entropy is shown to the user, with additional information
2424function() {
2425page.open(url, function(status) {
2426 // get text content from entropy sections of page
2427 var hasWarning = page.evaluate(function() {
2428 var entropyText = $(".entropy-container").text();
2429 var warning = "mnemonic may be insecure";
2430 if (entropyText.indexOf(warning) == -1) {
2431 return false;
2432 }
2433 var readMoreText = $("#entropy-notes").parent().text();
2434 var goodSources = "flipping a fair coin, rolling a fair dice, noise measurements etc";
2435 if (readMoreText.indexOf(goodSources) == -1) {
2436 return false;
2437 }
2438 return true;
2439 });
2440 // check the warnings and information are shown
2441 if (!hasWarning) {
2442 console.log("Page does not contain warning about using own entropy");
2443 fail();
2444 }
2445 next();
2446});
2447},
2448
2449// The types of entropy available are described to the user
2450function() {
2451page.open(url, function(status) {
2452 // get placeholder text for entropy field
2453 var placeholder = page.evaluate(function() {
2454 return $(".entropy").attr("placeholder");
2455 });
2456 var options = [
2457 "binary",
2458 "base 6",
2459 "dice",
2460 "base 10",
2461 "hexadecimal",
439f0e25 2462 "cards",
c6624d51
IC
2463 ];
2464 for (var i=0; i<options.length; i++) {
2465 var option = options[i];
2466 if (placeholder.indexOf(option) == -1) {
2467 console.log("Available entropy type is not shown to user: " + option);
2468 fail();
2469 }
2470 }
2471 next();
2472});
2473},
2474
2475// The actual entropy used is shown to the user
2476function() {
2477page.open(url, function(status) {
2478 // use entropy
2479 var badEntropySource = page.evaluate(function() {
2480 var entropy = "Not A Very Good Entropy Source At All";
2481 $(".use-entropy").prop("checked", true).trigger("change");
2482 $(".entropy").val(entropy).trigger("input");
2483 });
2484 // check the actual entropy being used is shown
057722b0 2485 waitForEntropyFeedback(function() {
c6624d51
IC
2486 var expectedText = "AedEceAA";
2487 var entropyText = page.evaluate(function() {
2488 return $(".entropy-container").text();
2489 });
2490 if (entropyText.indexOf(expectedText) == -1) {
2491 console.log("Actual entropy used is not shown");
2492 fail();
2493 }
2494 next();
2495 });
2496});
2497},
2498
2499// Binary entropy can be entered
2500function() {
2501page.open(url, function(status) {
2502 // use entropy
2503 page.evaluate(function() {
2504 $(".use-entropy").prop("checked", true).trigger("change");
2505 $(".entropy").val("01").trigger("input");
2506 });
2507 // check the entropy is shown to be the correct type
057722b0 2508 waitForEntropyFeedback(function() {
c6624d51
IC
2509 var entropyText = page.evaluate(function() {
2510 return $(".entropy-container").text();
2511 });
2512 if (entropyText.indexOf("binary") == -1) {
2513 console.log("Binary entropy is not detected and presented to user");
2514 fail();
2515 }
2516 next();
2517 });
2518});
2519},
2520
2521// Base 6 entropy can be entered
2522function() {
2523page.open(url, function(status) {
2524 // use entropy
2525 page.evaluate(function() {
2526 $(".use-entropy").prop("checked", true).trigger("change");
2527 $(".entropy").val("012345").trigger("input");
2528 });
2529 // check the entropy is shown to be the correct type
057722b0 2530 waitForEntropyFeedback(function() {
c6624d51
IC
2531 var entropyText = page.evaluate(function() {
2532 return $(".entropy-container").text();
2533 });
2534 if (entropyText.indexOf("base 6") == -1) {
2535 console.log("Base 6 entropy is not detected and presented to user");
2536 fail();
2537 }
2538 next();
2539 });
2540});
2541},
2542
2543// Base 6 dice entropy can be entered
2544function() {
2545page.open(url, function(status) {
2546 // use entropy
2547 page.evaluate(function() {
2548 $(".use-entropy").prop("checked", true).trigger("change");
2549 $(".entropy").val("123456").trigger("input");
2550 });
2551 // check the entropy is shown to be the correct type
057722b0 2552 waitForEntropyFeedback(function() {
c6624d51
IC
2553 var entropyText = page.evaluate(function() {
2554 return $(".entropy-container").text();
2555 });
2556 if (entropyText.indexOf("dice") == -1) {
2557 console.log("Dice entropy is not detected and presented to user");
2558 fail();
2559 }
2560 next();
2561 });
2562});
2563},
2564
2565// Base 10 entropy can be entered
2566function() {
2567page.open(url, function(status) {
2568 // use entropy
2569 page.evaluate(function() {
2570 $(".use-entropy").prop("checked", true).trigger("change");
2571 $(".entropy").val("789").trigger("input");
2572 });
2573 // check the entropy is shown to be the correct type
057722b0 2574 waitForEntropyFeedback(function() {
c6624d51
IC
2575 var entropyText = page.evaluate(function() {
2576 return $(".entropy-container").text();
2577 });
2578 if (entropyText.indexOf("base 10") == -1) {
2579 console.log("Base 10 entropy is not detected and presented to user");
2580 fail();
2581 }
2582 next();
2583 });
2584});
2585},
2586
2587// Hexadecimal entropy can be entered
2588function() {
2589page.open(url, function(status) {
2590 // use entropy
2591 page.evaluate(function() {
2592 $(".use-entropy").prop("checked", true).trigger("change");
2593 $(".entropy").val("abcdef").trigger("input");
2594 });
2595 // check the entropy is shown to be the correct type
057722b0 2596 waitForEntropyFeedback(function() {
c6624d51
IC
2597 var entropyText = page.evaluate(function() {
2598 return $(".entropy-container").text();
2599 });
2600 if (entropyText.indexOf("hexadecimal") == -1) {
2601 console.log("Hexadecimal entropy is not detected and presented to user");
2602 fail();
2603 }
2604 next();
2605 });
2606});
2607},
2608
2609// Dice entropy value is shown as the converted base 6 value
2610function() {
2611page.open(url, function(status) {
2612 // use entropy
2613 page.evaluate(function() {
2614 $(".use-entropy").prop("checked", true).trigger("change");
2615 $(".entropy").val("123456").trigger("input");
2616 });
2617 // check the entropy is shown as base 6, not as the original dice value
057722b0 2618 waitForEntropyFeedback(function() {
c6624d51
IC
2619 var entropyText = page.evaluate(function() {
2620 return $(".entropy-container").text();
2621 });
425b75a9 2622 if (entropyText.indexOf("123450") == -1) {
c6624d51
IC
2623 console.log("Dice entropy is not shown to user as base 6 value");
2624 fail();
2625 }
2626 if (entropyText.indexOf("123456") > -1) {
2627 console.log("Dice entropy value is shown instead of true base 6 value");
2628 fail();
2629 }
2630 next();
2631 });
2632});
2633},
2634
2635// The number of bits of entropy accumulated is shown
2636function() {
2637page.open(url, function(status) {
057722b0
IC
2638 //[ entropy, bits ]
2639 var tests = [
2640 [ "0000 0000 0000 0000 0000", "20" ],
2641 [ "0", "1" ],
2642 [ "0000", "4" ],
0d0f07f9
IC
2643 [ "6", "2" ], // 6 in card is 0 in base 6, 0 in base 6 is 2.6 bits (rounded down to 2 bits)
2644 [ "7", "3" ], // 7 in base 10 is 111 in base 2, no leading zeros
057722b0
IC
2645 [ "8", "4" ],
2646 [ "F", "4" ],
1cf1bbaf 2647 [ "29", "6" ],
057722b0
IC
2648 [ "0A", "8" ],
2649 [ "1A", "8" ], // hex is always multiple of 4 bits of entropy
2650 [ "2A", "8" ],
2651 [ "4A", "8" ],
2652 [ "8A", "8" ],
2653 [ "FA", "8" ],
2654 [ "000A", "16" ],
0d0f07f9
IC
2655 [ "5555", "11" ],
2656 [ "6666", "10" ], // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of 2.58 bits, which is 10.32 bits (rounded down to 10 bits)
1cf1bbaf 2657 [ "2227", "13" ], // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded down to 13)
057722b0
IC
2658 [ "222F", "16" ],
2659 [ "FFFF", "16" ],
1cf1bbaf 2660 [ "0000101017", "33" ], // 10 events at 3.32 bits per event
6422c1cd 2661 [ "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "225" ], // cards are not replaced, so a full deck is not 52^52 entropy which is 296 bits, it's 52!, which is 225 bits
057722b0 2662 ]
c6624d51
IC
2663 // use entropy
2664 page.evaluate(function(e) {
2665 $(".use-entropy").prop("checked", true).trigger("change");
2666 });
2667 // Run each test
2668 var nextTest = function runNextTest(i) {
057722b0
IC
2669 var entropy = tests[i][0];
2670 var expected = tests[i][1];
c6624d51
IC
2671 // set entropy
2672 page.evaluate(function(e) {
c6624d51
IC
2673 $(".entropy").val(e).trigger("input");
2674 }, entropy);
2675 // check the number of bits of entropy is shown
057722b0 2676 waitForEntropyFeedback(function() {
c6624d51 2677 var entropyText = page.evaluate(function() {
dd944906 2678 return $(".entropy-container").text();
c6624d51 2679 });
1cf1bbaf 2680 if (entropyText.replace(/\s/g,"").indexOf("Bits" + expected) == -1) {
c6624d51
IC
2681 console.log("Accumulated entropy is not shown correctly for " + entropy);
2682 fail();
2683 }
057722b0 2684 var isLastTest = i == tests.length - 1;
c6624d51
IC
2685 if (isLastTest) {
2686 next();
2687 }
2688 else {
2689 runNextTest(i+1);
2690 }
2691 });
2692 }
2693 nextTest(0);
2694});
2695},
2696
fb353f9d 2697// There is feedback provided about the supplied entropy
c6624d51
IC
2698function() {
2699page.open(url, function(status) {
2700 var tests = [
2701 {
2702 entropy: "A",
fb353f9d
IC
2703 filtered: "A",
2704 type: "hexadecimal",
2705 events: 1,
2706 bits: 4,
c6624d51 2707 words: 0,
1cf1bbaf 2708 strength: "extremely weak",
c6624d51
IC
2709 },
2710 {
2711 entropy: "AAAAAAAA",
fb353f9d
IC
2712 filtered: "AAAAAAAA",
2713 type: "hexadecimal",
2714 events: 8,
2715 bits: 32,
c6624d51 2716 words: 3,
1cf1bbaf 2717 strength: "extremely weak",
c6624d51
IC
2718 },
2719 {
2720 entropy: "AAAAAAAA B",
fb353f9d
IC
2721 filtered: "AAAAAAAAB",
2722 type: "hexadecimal",
2723 events: 9,
2724 bits: 36,
c6624d51 2725 words: 3,
1cf1bbaf 2726 strength: "extremely weak",
c6624d51
IC
2727 },
2728 {
2729 entropy: "AAAAAAAA BBBBBBBB",
fb353f9d
IC
2730 filtered: "AAAAAAAABBBBBBBB",
2731 type: "hexadecimal",
2732 events: 16,
2733 bits: 64,
c6624d51 2734 words: 6,
1cf1bbaf 2735 strength: "very weak",
c6624d51
IC
2736 },
2737 {
2738 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
fb353f9d
IC
2739 filtered: "AAAAAAAABBBBBBBBCCCCCCCC",
2740 type: "hexadecimal",
2741 events: 24,
2742 bits: 96,
c6624d51 2743 words: 9,
1cf1bbaf 2744 strength: "weak",
c6624d51
IC
2745 },
2746 {
2747 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
fb353f9d
IC
2748 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD",
2749 type: "hexadecimal",
2750 events: 32,
2751 bits: 128,
c6624d51 2752 words: 12,
e6a799cc
IC
2753 strength: "easily cracked",
2754 },
2755 {
2756 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA",
2757 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDA",
2758 type: "hexadecimal",
2759 events: 32,
2760 bits: 128,
2761 words: 12,
1cf1bbaf 2762 strength: "strong",
c6624d51
IC
2763 },
2764 {
e6a799cc
IC
2765 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE",
2766 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEE",
fb353f9d
IC
2767 type: "hexadecimal",
2768 events: 40,
2769 bits: 160,
c6624d51 2770 words: 15,
1cf1bbaf
IC
2771 strength: "very strong",
2772 },
2773 {
e6a799cc
IC
2774 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE FFFFFFFF",
2775 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEEFFFFFFFF",
fb353f9d
IC
2776 type: "hexadecimal",
2777 events: 48,
2778 bits: 192,
1cf1bbaf
IC
2779 words: 18,
2780 strength: "extremely strong",
fb353f9d 2781 },
391c7f26
IC
2782 {
2783 entropy: "7d",
2784 type: "card",
2785 events: 1,
2786 bits: 5,
2787 words: 0,
2788 strength: "extremely weak",
2789 },
2790 {
2791 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2792 type: "card (full deck)",
2793 events: 52,
6422c1cd
IC
2794 bits: 225,
2795 words: 21,
391c7f26
IC
2796 strength: "extremely strong",
2797 },
2798 {
2799 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d",
2800 type: "card (full deck, 1 duplicate: 3d)",
2801 events: 53,
87ad2c6e 2802 bits: 254,
6422c1cd 2803 words: 21,
391c7f26
IC
2804 strength: "extremely strong",
2805 },
2806 {
2807 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d",
bbc29c80 2808 type: "card (2 duplicates: 3d 4d, 1 missing: KS)",
391c7f26 2809 events: 53,
87ad2c6e 2810 bits: 254,
6422c1cd 2811 words: 21,
391c7f26
IC
2812 strength: "extremely strong",
2813 },
2814 {
2815 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d",
bbc29c80 2816 type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)",
391c7f26 2817 events: 53,
87ad2c6e
IC
2818 bits: 264,
2819 words: 24,
391c7f26
IC
2820 strength: "extremely strong",
2821 },
9bc39377 2822 // Next test was throwing uncaught error in zxcvbn
6422c1cd 2823 // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2
9bc39377
IC
2824 {
2825 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2826 type: "card (full deck, 52 duplicates: ac 2c 3c...)",
2827 events: 104,
87ad2c6e
IC
2828 bits: 499,
2829 words: 45,
9bc39377
IC
2830 strength: "extremely strong",
2831 },
5c653a12
IC
2832 // Case insensitivity to duplicate cards
2833 {
2834 entropy: "asAS",
2835 type: "card (1 duplicate: AS)",
2836 events: 2,
87ad2c6e 2837 bits: 9,
5c653a12
IC
2838 words: 0,
2839 strength: "extremely weak",
2840 },
2841 {
2842 entropy: "ASas",
2843 type: "card (1 duplicate: as)",
2844 events: 2,
87ad2c6e 2845 bits: 9,
5c653a12
IC
2846 words: 0,
2847 strength: "extremely weak",
2848 },
bbc29c80
IC
2849 // Missing cards are detected
2850 {
2851 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2852 type: "card (1 missing: 9C)",
2853 events: 51,
87ad2c6e
IC
2854 bits: 221,
2855 words: 18,
bbc29c80
IC
2856 strength: "extremely strong",
2857 },
2858 {
2859 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2860 type: "card (2 missing: 9C 5D)",
2861 events: 50,
87ad2c6e
IC
2862 bits: 216,
2863 words: 18,
bbc29c80
IC
2864 strength: "extremely strong",
2865 },
2866 {
2867 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2868 type: "card (4 missing: 9C 5D QD...)",
2869 events: 48,
87ad2c6e 2870 bits: 208,
6422c1cd 2871 words: 18,
bbc29c80
IC
2872 strength: "extremely strong",
2873 },
2874 // More than six missing cards does not show message
2875 {
2876 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks",
2877 type: "card",
2878 events: 45,
87ad2c6e 2879 bits: 195,
6422c1cd 2880 words: 18,
bbc29c80
IC
2881 strength: "extremely strong",
2882 },
fc7c248f
IC
2883 // Multiple decks of cards increases bits per event
2884 {
2885 entropy: "3d",
2886 events: 1,
2887 bits: 4,
2888 bitsPerEvent: 4.34,
2889 },
2890 {
2891 entropy: "3d3d",
2892 events: 2,
2893 bits: 9,
2894 bitsPerEvent: 4.80,
2895 },
2896 {
2897 entropy: "3d3d3d",
2898 events: 3,
2899 bits: 15,
2900 bitsPerEvent: 5.01,
2901 },
2902 {
2903 entropy: "3d3d3d3d",
2904 events: 4,
2905 bits: 20,
2906 bitsPerEvent: 5.14,
2907 },
2908 {
2909 entropy: "3d3d3d3d3d",
2910 events: 5,
2911 bits: 26,
2912 bitsPerEvent: 5.22,
2913 },
2914 {
2915 entropy: "3d3d3d3d3d3d",
2916 events: 6,
2917 bits: 31,
2918 bitsPerEvent: 5.28,
2919 },
2920 {
2921 entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d",
2922 events: 33,
2923 bits: 184,
2924 bitsPerEvent: 5.59,
2925 strength: 'easily cracked - Repeats like "abcabcabc" are only slightly harder to guess than "abc"',
2926 },
c6624d51
IC
2927 ];
2928 // use entropy
2929 page.evaluate(function() {
2930 $(".use-entropy").prop("checked", true).trigger("change");
2931 });
2932 var nextTest = function runNextTest(i) {
fb353f9d 2933 function getFeedbackError(expected, actual) {
391c7f26 2934 if ("filtered" in expected && actual.indexOf(expected.filtered) == -1) {
fb353f9d
IC
2935 return "Filtered value not in feedback";
2936 }
fc7c248f 2937 if ("type" in expected && actual.indexOf(expected.type) == -1) {
fb353f9d
IC
2938 return "Entropy type not in feedback";
2939 }
fc7c248f 2940 if ("events" in expected && actual.indexOf(expected.events) == -1) {
fb353f9d
IC
2941 return "Event count not in feedback";
2942 }
fc7c248f 2943 if ("bits" in expected && actual.indexOf(expected.bits) == -1) {
fb353f9d
IC
2944 return "Bit count not in feedback";
2945 }
fc7c248f 2946 if ("strength" in expected && actual.indexOf(expected.strength) == -1) {
fb353f9d
IC
2947 return "Strength not in feedback";
2948 }
fc7c248f
IC
2949 if ("bitsPerEvent" in expected && actual.indexOf(expected.bitsPerEvent) == -1) {
2950 return "bitsPerEvent not in feedback";
2951 }
fb353f9d
IC
2952 return false;
2953 }
c6624d51
IC
2954 test = tests[i];
2955 page.evaluate(function(e) {
2956 $(".addresses").empty();
057722b0 2957 $(".phrase").val("");
c6624d51
IC
2958 $(".entropy").val(e).trigger("input");
2959 }, test.entropy);
fb353f9d 2960 waitForEntropyFeedback(function() {
c6624d51
IC
2961 var mnemonic = page.evaluate(function() {
2962 return $(".phrase").val();
2963 });
fb353f9d 2964 // Check mnemonic length
fc7c248f 2965 if ("words" in test && test.words == 0) {
fb353f9d
IC
2966 if (mnemonic.length > 0) {
2967 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
87ad2c6e 2968 console.log("Entropy: " + test.entropy);
fb353f9d
IC
2969 console.log("Mnemonic: " + mnemonic);
2970 fail();
2971 }
2972 }
fc7c248f 2973 else if ("words" in test) {
fb353f9d
IC
2974 if (mnemonic.split(" ").length != test.words) {
2975 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
87ad2c6e 2976 console.log("Entropy: " + test.entropy);
fb353f9d
IC
2977 console.log("Mnemonic: " + mnemonic);
2978 fail();
2979 }
2980 }
2981 // check feedback
2982 var feedback = page.evaluate(function() {
dd944906 2983 return $(".entropy-container").text();
fb353f9d
IC
2984 });
2985 var feedbackError = getFeedbackError(test, feedback);
2986 if (feedbackError) {
2987 console.log("Entropy feedback for " + test.entropy + " returned error");
2988 console.log(feedbackError);
c6624d51
IC
2989 fail();
2990 }
fb353f9d 2991 // Run next test
c6624d51
IC
2992 var isLastTest = i == tests.length - 1;
2993 if (isLastTest) {
2994 next();
2995 }
2996 else {
2997 runNextTest(i+1);
2998 }
fb353f9d 2999 });
c6624d51
IC
3000 }
3001 nextTest(0);
3002});
3003},
3004
d6fd8ebf 3005// Entropy is truncated from the left
c6624d51
IC
3006function() {
3007page.open(url, function(status) {
d6fd8ebf 3008 var expected = "avocado zoo zone";
c6624d51
IC
3009 // use entropy
3010 page.evaluate(function() {
3011 $(".use-entropy").prop("checked", true).trigger("change");
3012 var entropy = "00000000 00000000 00000000 00000000";
d6fd8ebf 3013 entropy += "11111111 11111111 11111111 1111"; // Missing last byte
c6624d51
IC
3014 $(".entropy").val(entropy).trigger("input");
3015 });
3016 // check the entropy is truncated from the right
3017 waitForGenerate(function() {
3018 var actual = page.evaluate(function() {
3019 return $(".phrase").val();
3020 });
3021 if (actual != expected) {
3022 console.log("Entropy is not truncated from the right");
3023 console.log("Expected: " + expected);
3024 console.log("Got: " + actual);
3025 fail();
3026 }
3027 next();
3028 });
3029});
3030},
3031
3032// Very large entropy results in very long mnemonics
3033function() {
3034page.open(url, function(status) {
3035 // use entropy
3036 page.evaluate(function() {
3037 $(".use-entropy").prop("checked", true).trigger("change");
3038 var entropy = "";
3039 // Generate a very long entropy string
3040 for (var i=0; i<33; i++) {
3041 entropy += "AAAAAAAA"; // 3 words * 33 iterations = 99 words
3042 }
3043 $(".entropy").val(entropy).trigger("input");
3044 });
3045 // check the mnemonic is very long
3046 waitForGenerate(function() {
3047 var wordCount = page.evaluate(function() {
3048 return $(".phrase").val().split(" ").length;
3049 });
3050 if (wordCount != 99) {
3051 console.log("Large entropy does not generate long mnemonic");
3052 console.log("Expected 99 words, got " + wordCount);
3053 fail();
3054 }
3055 next();
3056 });
3057});
3058},
3059
3060// Is compatible with bip32jp entropy
3061// https://bip32jp.github.io/english/index.html
3062// NOTES:
3063// Is incompatible with:
c6624d51
IC
3064// base 20
3065function() {
3066page.open(url, function(status) {
0d0f07f9 3067 var expected = "train then jungle barely whip fiber purpose puppy eagle cloud clump hospital robot brave balcony utility detect estate old green desk skill multiply virus";
c6624d51
IC
3068 // use entropy
3069 page.evaluate(function() {
3070 $(".use-entropy").prop("checked", true).trigger("change");
0d0f07f9 3071 var entropy = "543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543";
c6624d51
IC
3072 $(".entropy").val(entropy).trigger("input");
3073 });
3074 // check the mnemonic matches the expected value from bip32jp
3075 waitForGenerate(function() {
3076 var actual = page.evaluate(function() {
3077 return $(".phrase").val();
3078 });
3079 if (actual != expected) {
3080 console.log("Mnemonic does not match bip32jp for base 6 entropy");
3081 console.log("Expected: " + expected);
3082 console.log("Got: " + actual);
3083 fail();
3084 }
3085 next();
3086 });
3087});
3088},
3089
057722b0
IC
3090// Blank entropy does not generate mnemonic or addresses
3091function() {
3092page.open(url, function(status) {
3093 // use entropy
3094 page.evaluate(function() {
3095 $(".use-entropy").prop("checked", true).trigger("change");
3096 $(".entropy").val("").trigger("input");
3097 });
3098 waitForFeedback(function() {
3099 // check there is no mnemonic
3100 var phrase = page.evaluate(function() {
3101 return $(".phrase").val();
3102 });
3103 if (phrase != "") {
3104 console.log("Blank entropy does not result in blank mnemonic");
3105 console.log("Got: " + phrase);
3106 fail();
3107 }
3108 // check there are no addresses displayed
3109 var addresses = page.evaluate(function() {
3110 return $(".address").length;
3111 });
3112 if (addresses != 0) {
3113 console.log("Blank entropy does not result in zero addresses");
3114 fail();
3115 }
3116 // Check the feedback says 'blank entropy'
3117 var feedback = page.evaluate(function() {
3118 return $(".feedback").text();
3119 });
3120 if (feedback != "Blank entropy") {
3121 console.log("Blank entropy does not show feedback message");
3122 fail();
3123 }
3124 next();
3125 });
3126});
3127},
3128
3599674d
IC
3129// Mnemonic length can be selected even for weak entropy
3130function() {
3131page.open(url, function(status) {
3132 // use entropy
3133 page.evaluate(function() {
3134 $(".use-entropy").prop("checked", true).trigger("change");
3135 $(".entropy").val("012345");
3136 $(".mnemonic-length").val("18").trigger("change");
3137 });
3138 // check the mnemonic is the correct length
3139 waitForGenerate(function() {
3140 var phrase = page.evaluate(function() {
3141 return $(".phrase").val();
3142 });
3143 var numberOfWords = phrase.split(/\s/g).length;
3144 if (numberOfWords != 18) {
3145 console.log("Weak entropy cannot be overridden to give 18 word mnemonic");
3146 console.log(phrase);
3147 fail();
3148 }
3149 next();
3150 });
3151});
3152},
3153
886f06ee
IC
3154// Github issue 33
3155// https://github.com/iancoleman/bip39/issues/33
3156// Final cards should contribute entropy
3157function() {
3158page.open(url, function(status) {
3159 // use entropy
3160 page.evaluate(function() {
3161 $(".use-entropy").prop("checked", true).trigger("change");
3162 $(".entropy").val("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-6C TS TH 4H KC 5H 2H AH 2C 8D 3H 5D").trigger("input");
3163 });
3164 // get the mnemonic
3165 waitForGenerate(function() {
3166 var originalPhrase = page.evaluate(function() {
3167 return $(".phrase").val();
3168 });
3169 // Set the last 12 cards to be AS
3170 page.evaluate(function() {
3171 $(".addresses").empty();
3172 $(".entropy").val("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-AS AS AS AS AS AS AS AS AS AS AS AS").trigger("input");
3173 });
3174 // get the new mnemonic
3175 waitForGenerate(function() {
3176 var newPhrase = page.evaluate(function() {
3177 return $(".phrase").val();
3178 });
92e73fd9 3179 // check the phrase has changed
886f06ee
IC
3180 if (newPhrase == originalPhrase) {
3181 console.log("Changing last 12 cards does not change mnemonic");
3182 console.log("Original:");
3183 console.log(originalPhrase);
3184 console.log("New:");
3185 console.log(newPhrase);
3186 fail();
3187 }
3188 next();
3189 });
3190 });
3191});
3192},
3193
e00964cc
IC
3194// Github issue 35
3195// https://github.com/iancoleman/bip39/issues/35
3196// QR Code support
3197function() {
3198page.open(url, function(status) {
3199 // use entropy
3200 page.evaluate(function() {
3201 $(".generate").click();
3202 });
3203 waitForGenerate(function() {
3204 var p = page.evaluate(function() {
3205 // get position of mnemonic element
3206 return $(".phrase").offset();
3207 });
3208 p.top = Math.ceil(p.top);
3209 p.left = Math.ceil(p.left);
3210 // check the qr code shows
3211 page.sendEvent("mousemove", p.left+4, p.top+4);
3212 var qrShowing = page.evaluate(function() {
3213 return $(".qr-container").find("canvas").length > 0;
3214 });
3215 if (!qrShowing) {
3216 console.log("QR Code does not show");
3217 fail();
3218 }
3219 // check the qr code hides
3220 page.sendEvent("mousemove", p.left-4, p.top-4);
3221 var qrHidden = page.evaluate(function() {
3222 return $(".qr-container").find("canvas").length == 0;
3223 });
3224 if (!qrHidden) {
3225 console.log("QR Code does not hide");
3226 fail();
3227 }
3228 next();
3229 });
3230});
3231},
3232
c554e6ff
IC
3233// BIP44 account extendend private key is shown
3234// github issue 37 - compatibility with electrum
3235function() {
3236page.open(url, function(status) {
3237 // set the phrase
3238 var expected = "xprv9yzrnt4zWVJUr1k2VxSPy9ettKz5PpeDMgaVG7UKedhqnw1tDkxP2UyYNhuNSumk2sLE5ctwKZs9vwjsq3e1vo9egCK6CzP87H2cVYXpfwQ";
3239 page.evaluate(function() {
3240 $(".phrase").val("abandon abandon ability");
3241 $(".phrase").trigger("input");
3242 });
3243 // check the BIP44 account extended private key
3244 waitForGenerate(function() {
3245 var actual = page.evaluate(function() {
3246 return $(".account-xprv").val();
3247 });
3248 if (actual != expected) {
3249 console.log("BIP44 account extended private key is incorrect");
3250 console.log("Expected: " + expected);
3251 console.log("Actual: " + actual);
3252 fail();
3253 }
3254 next();
3255 });
3256});
3257},
3258
3259// BIP44 account extendend public key is shown
3260// github issue 37 - compatibility with electrum
3261function() {
3262page.open(url, function(status) {
3263 // set the phrase
3264 var expected = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3265 page.evaluate(function() {
3266 $(".phrase").val("abandon abandon ability");
3267 $(".phrase").trigger("input");
3268 });
3269 // check the BIP44 account extended public key
3270 waitForGenerate(function() {
3271 var actual = page.evaluate(function() {
3272 return $(".account-xpub").val();
3273 });
3274 if (actual != expected) {
3275 console.log("BIP44 account extended public key is incorrect");
3276 console.log("Expected: " + expected);
ba3cb9ec
IC
3277 console.log("Actual: " + actual);
3278 fail();
3279 }
3280 next();
3281 });
3282});
3283},
3284
3285// github issue 40
3286// BIP32 root key can be set as an xpub
3287function() {
3288page.open(url, function(status) {
3289 // set the phrase
3290 page.evaluate(function() {
3291 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3292 var bip44AccountXpub = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3293 $("#root-key").val(bip44AccountXpub);
3294 $("#root-key").trigger("input");
3295 });
3296 waitForFeedback(function() {
3297 page.evaluate(function() {
3298 // Use bip32 tab
3299 $("#bip32-tab a").click();
3300 });
3301 waitForGenerate(function() {
3302 page.evaluate(function() {
3303 // derive external addresses for this xpub
3304 var firstAccountDerivationPath = "m/0";
3305 $("#bip32-path").val(firstAccountDerivationPath);
3306 $("#bip32-path").trigger("input");
3307 });
3308 waitForGenerate(function() {
3309 // check the addresses are generated
3310 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
3311 var actual = page.evaluate(function() {
3312 return $(".address:first").text();
3313 });
3314 if (actual != expected) {
3315 console.log("xpub key does not generate addresses in table");
3316 console.log("Expected: " + expected);
3317 console.log("Actual: " + actual);
3318 fail();
3319 }
3320 // check the xprv key is not set
3321 var expected = "NA";
3322 var actual = page.evaluate(function() {
3323 return $(".extended-priv-key").val();
3324 });
3325 if (actual != expected) {
3326 console.log("xpub key as root shows derived bip32 xprv key");
3327 console.log("Expected: " + expected);
3328 console.log("Actual: " + actual);
3329 fail();
3330 }
3331 // check the private key is not set
3332 var expected = "NA";
3333 var actual = page.evaluate(function() {
3334 return $(".privkey:first").text();
3335 });
3336 if (actual != expected) {
3337 console.log("xpub key generates private key in addresses table");
3338 console.log("Expected: " + expected);
3339 console.log("Actual: " + actual);
3340 fail();
3341 }
3342 next();
3343 });
3344 });
3345 });
3346});
3347},
3348
3349// github issue 40
3350// xpub for bip32 root key will not work with hardened derivation paths
3351function() {
3352page.open(url, function(status) {
3353 // set the phrase
3354 page.evaluate(function() {
3355 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3356 var bip44AccountXpub = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3357 $("#root-key").val(bip44AccountXpub);
3358 $("#root-key").trigger("input");
3359 });
3360 waitForFeedback(function() {
3361 // Check feedback is correct
3362 var expected = "Hardened derivation path is invalid with xpub key";
3363 var actual = page.evaluate(function() {
3364 return $(".feedback").text();
3365 });
3366 if (actual != expected) {
3367 console.log("xpub key with hardened derivation path does not show feedback");
3368 console.log("Expected: " + expected);
3369 console.log("Actual: " + actual);
3370 fail();
3371 }
3372 // Check no addresses are shown
3373 var expected = 0;
3374 var actual = page.evaluate(function() {
3375 return $(".addresses tr").length;
3376 });
3377 if (actual != expected) {
3378 console.log("addresses still show after setting xpub key with hardened derivation path");
3379 console.log("Expected: " + expected);
c554e6ff
IC
3380 console.log("Actual: " + actual);
3381 fail();
3382 }
3383 next();
3384 });
3385});
3386},
3387
0a1f0259
IC
3388// github issue 39
3389// no root key shows feedback
3390function() {
3391page.open(url, function(status) {
3392 // click the bip32 tab on fresh page
3393 page.evaluate(function() {
3394 $("#bip32-tab a").click();
3395 });
3396 waitForFeedback(function() {
3397 // Check feedback is correct
3398 var expected = "No root key";
3399 var actual = page.evaluate(function() {
3400 return $(".feedback").text();
3401 });
3402 if (actual != expected) {
3403 console.log("Blank root key not detected");
3404 console.log("Expected: " + expected);
3405 console.log("Actual: " + actual);
3406 fail();
3407 }
3408 next();
3409 });
3410});
3411},
886f06ee 3412
40892aba
IC
3413// Github issue 44
3414// display error switching tabs while addresses are generating
3415function() {
3416page.open(url, function(status) {
3417 // set the phrase
3418 page.evaluate(function() {
3419 $(".phrase").val("abandon abandon ability").trigger("input");
3420 });
3421 waitForGenerate(function() {
3422 // set to generate 500 more addresses
3423 // generate more addresses
3424 // change tabs which should cancel the previous generating
3425 page.evaluate(function() {
3426 $(".rows-to-add").val("100");
3427 $(".more").click();
3428 $("#bip32-tab a").click();
3429 });
3430 // check the derivation paths are in order and of the right quantity
3431 waitForGenerate(function() {
3432 var paths = page.evaluate(function() {
3433 return $(".index").map(function(i, e) {
3434 return $(e).text();
3435 });
3436 });
3437 for (var i=0; i<paths.length; i++) {
3438 var expected = "m/0/" + i;
3439 var actual = paths[i];
3440 if (actual != expected) {
3441 console.log("Path " + i + " is not in correct order");
3442 console.log("Expected: " + expected);
3443 console.log("Actual: " + actual);
3444 fail();
3445 }
3446 }
3447 if (paths.length != 20) {
3448 console.log("Generation was not cancelled by new action");
3449 fail();
3450 }
3451 next();
3452 });
3453 });
3454});
3455},
3456
53aaab27
IC
3457// Github issue 49
3458// padding for binary should give length with multiple of 256
3459// hashed entropy 1111 is length 252, so requires 4 leading zeros
3460// prior to issue 49 it would only generate 2 leading zeros, ie missing 2
3461function() {
3462page.open(url, function(status) {
3463 expected = "avocado valid quantum cross link predict excuse edit street able flame large galaxy ginger nuclear"
3464 // use entropy
3465 page.evaluate(function() {
3466 $(".use-entropy").prop("checked", true).trigger("change");
5ed50bd9 3467 $(".mnemonic-length").val("15");
53aaab27
IC
3468 $(".entropy").val("1111").trigger("input");
3469 });
3470 waitForGenerate(function() {
3471 // get the mnemonic
3472 var actual = page.evaluate(function() {
3473 return $(".phrase").val();
3474 });
3475 // check the mnemonic is correct
3476 if (actual != expected) {
3477 console.log("Left padding error for entropy");
3478 console.log("Expected: " + expected);
3479 console.log("Actual: " + actual);
3480 fail();
3481 }
3482 next();
3483 });
3484});
3485},
3486
cdfaaf00
IC
3487// Github pull request 55
3488// https://github.com/iancoleman/bip39/pull/55
3489// Client select
3490function() {
3491page.open(url, function(status) {
3492 // set mnemonic and select bip32 tab
3493 page.evaluate(function() {
3494 $("#bip32-tab a").click();
3495 $(".phrase").val("abandon abandon ability").trigger("input");
3496 });
3497 waitForGenerate(function() {
3498 // BITCOIN CORE
3499 // set bip32 client to bitcoin core
3500 page.evaluate(function() {
3501 var bitcoinCoreIndex = "0";
3502 $("#bip32-client").val(bitcoinCoreIndex).trigger("change");
3503 });
3504 waitForGenerate(function() {
3505 // get the derivation path
3506 var actual = page.evaluate(function() {
3507 return $("#bip32-path").val();
3508 });
3509 // check the derivation path is correct
3510 expected = "m/0'/0'"
3511 if (actual != expected) {
3512 console.log("Selecting Bitcoin Core client does not set correct derivation path");
3513 console.log("Expected: " + expected);
3514 console.log("Actual: " + actual);
3515 fail();
3516 }
3517 // get hardened addresses
3518 var usesHardenedAddresses = page.evaluate(function() {
3519 return $(".hardened-addresses").prop("checked");
3520 });
3521 // check hardened addresses is selected
3522 if(!usesHardenedAddresses) {
3523 console.log("Selecting Bitcoin Core client does not use hardened addresses");
3524 fail();
3525 }
3526 // check input is readonly
3527 var pathIsReadonly = page.evaluate(function() {
3528 return $("#bip32-path").prop("readonly");
3529 });
3530 if (!pathIsReadonly) {
3531 console.log("Selecting Bitcoin Core client does not set derivation path to readonly");
3532 fail();
3533 }
3534 // MULTIBIT
3535 // set bip32 client to multibit
3536 page.evaluate(function() {
3537 var multibitIndex = "2";
3538 $("#bip32-client").val(multibitIndex).trigger("change");
3539 });
3540 waitForGenerate(function() {
3541 // get the derivation path
3542 var actual = page.evaluate(function() {
3543 return $("#bip32-path").val();
3544 });
3545 // check the derivation path is correct
3546 expected = "m/0'/0"
3547 if (actual != expected) {
3548 console.log("Selecting Multibit client does not set correct derivation path");
3549 console.log("Expected: " + expected);
3550 console.log("Actual: " + actual);
3551 fail();
3552 }
3553 // get hardened addresses
3554 var usesHardenedAddresses = page.evaluate(function() {
3555 return $(".hardened-addresses").prop("checked");
3556 });
3557 // check hardened addresses is selected
3558 if(usesHardenedAddresses) {
3559 console.log("Selecting Multibit client does not uncheck hardened addresses");
3560 fail();
3561 }
3562 // CUSTOM DERIVATION PATH
3563 // check input is not readonly
3564 page.evaluate(function() {
3565 $("#bip32-client").val("custom").trigger("change");
3566 });
3567 // do not wait for generate, since there is no change to the
3568 // derivation path there is no new generation performed
3569 var pathIsReadonly = page.evaluate(function() {
3570 return $("#bip32-path").prop("readonly");
3571 });
3572 if (pathIsReadonly) {
3573 console.log("Selecting Custom Derivation Path does not allow derivation path input");
3574 fail();
3575 }
3576 next();
3577 });
3578 });
3579 });
3580});
3581},
3582
e6f08c6a
IC
3583// github issue 58
3584// https://github.com/iancoleman/bip39/issues/58
3585// bip32 derivation is correct, does not drop leading zeros
3586// see also
3587// https://medium.com/@alexberegszaszi/why-do-my-bip32-wallets-disagree-6f3254cc5846
3588function() {
3589page.open(url, function(status) {
3590 // set the phrase and passphrase
3591 var expected = "17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F";
3592 // Note that bitcore generates an incorrect address
3593 // 13EuKhffWkBE2KUwcbkbELZb1MpzbimJ3Y
3594 // see the medium.com link above for more details
3595 page.evaluate(function() {
3596 $(".phrase").val("fruit wave dwarf banana earth journey tattoo true farm silk olive fence");
3597 $(".passphrase").val("banana").trigger("input");
3598 });
3599 // check the address is generated correctly
3600 waitForGenerate(function() {
3601 var actual = page.evaluate(function() {
3602 return $(".address:first").text();
3603 });
3604 if (actual != expected) {
3605 console.log("BIP32 derivation is incorrect");
3606 console.log("Expected: " + expected);
d2d98ef7
IC
3607 console.log("Actual: " + actual);
3608 fail();
3609 }
3610 next();
3611 });
3612});
3613},
3614
3615
3616// github issue 60
3617// Japanese mnemonics generate incorrect bip32 seed
3618// BIP39 seed is set from phrase
3619function() {
3620page.open(url, function(status) {
3621 // set the phrase
3622 var expected = "a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55";
3623 page.evaluate(function() {
3624 $(".phrase").val("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら");
3625 $("#passphrase").val("メートルガバヴァぱばぐゞちぢ十人十色");
3626 $("#passphrase").trigger("input");
3627 });
3628 // check the seed is generated correctly
3629 waitForGenerate(function() {
3630 var actual = page.evaluate(function() {
3631 return $(".seed").val();
3632 });
3633 if (actual != expected) {
3634 console.log("BIP39 seed is incorrectly generated from Japanese mnemonic");
3635 console.log("Expected: " + expected);
e6f08c6a
IC
3636 console.log("Actual: " + actual);
3637 fail();
3638 }
3639 next();
3640 });
3641});
3642},
3643
b0fb45b9
IC
3644// If you wish to add more tests, do so here...
3645
3646// Here is a blank test template
3647/*
3648
3649function() {
3650page.open(url, function(status) {
3651 // Do something on the page
3652 page.evaluate(function() {
3653 $(".phrase").val("abandon abandon ability").trigger("input");
3654 });
3655 waitForGenerate(function() {
3656 // Check the result of doing the thing
3657 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
3658 var actual = page.evaluate(function() {
3659 return $(".address:first").text();
3660 });
3661 if (actual != expected) {
3662 console.log("A specific message about what failed");
3663 console.log("Expected: " + expected);
3664 console.log("Actual: " + actual);
3665 fail();
3666 }
3667 // Run the next test
3668 next();
3669 });
3670});
3671},
3672
3673*/
3674
88e2cdaa
IC
3675];
3676
3677console.log("Running tests...");
fb372687 3678tests = shuffle(tests);
88e2cdaa 3679next();