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