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