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