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