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