aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml17
-rw-r--r--app/_locales/ja/messages.json76
-rw-r--r--app/_locales/zh_TW/messages.json61
-rw-r--r--package-lock.json175
-rw-r--r--package.json5
-rw-r--r--test/e2e/func.js18
-rw-r--r--test/e2e/metamask.spec.js122
7 files changed, 448 insertions, 26 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index c14909783..8ebf569a5 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -12,6 +12,9 @@ workflows:
- test-lint:
requires:
- prep-deps-npm
+ - test-e2e:
+ requires:
+ - prep-deps-npm
- test-unit:
requires:
- prep-deps-npm
@@ -96,6 +99,20 @@ jobs:
name: Test
command: npm run lint
+ test-e2e:
+ docker:
+ - image: circleci/node:8-browsers
+ steps:
+ - checkout
+ - restore_cache:
+ key: dependency-cache-{{ checksum "package-lock.json" }}
+ - run:
+ name: Build
+ command: npm run dist
+ - run:
+ name: Test
+ command: npm run test:e2e
+
test-unit:
docker:
- image: circleci/node:8-browsers
diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json
index bab8d3b95..d9762a3e9 100644
--- a/app/_locales/ja/messages.json
+++ b/app/_locales/ja/messages.json
@@ -14,6 +14,9 @@
"address": {
"message": "アドレス"
},
+ "addCustomToken": {
+ "message": "カスタムトークンを追加"
+ },
"addToken": {
"message": "トークンを追加"
},
@@ -63,11 +66,14 @@
"message": "Coinbaseで購入"
},
"buyCoinbaseExplainer": {
- "message": "Coinbaseは、世界で最もポピュラーなBitcoin、Ethereum、そしてLitecoinの取引所です。"
+ "message": "Coinbaseは、世界的なBitcoin、Ethereum、そしてLitecoinの取引所です。"
},
"cancel": {
"message": "キャンセル"
},
+ "classicInterface": {
+ "message": "旧インタフェイスを使用"
+ },
"clickCopy": {
"message": "クリックしてコピー"
},
@@ -126,6 +132,9 @@
"message": "暗号通貨",
"description": "Exchange type (cryptocurrencies)"
},
+ "currentConversion": {
+ "message": "基軸通貨"
+ },
"customGas": {
"message": "ガスのカスタマイズ"
},
@@ -135,14 +144,17 @@
"customRPC": {
"message": "カスタムRPC"
},
+ "decimal": {
+ "message": "小数点桁数"
+ },
"defaultNetwork": {
- "message": "Etherトランザクションのデフォルトのネットワークはメインネットです。"
+ "message": "デフォルトのEther送受信ネットワークはメインネットです。"
},
"denExplainer": {
"message": "DENとは、あなたのパスワードが暗号化されたMetaMask内のストレージです。"
},
"deposit": {
- "message": "デポジット"
+ "message": "受取り"
},
"depositBTC": {
"message": "あなたのBTCを次のアドレスへデポジット:"
@@ -161,13 +173,13 @@
"message": "法定通貨でデポジット"
},
"depositFromAccount": {
- "message": "別のアカウントからデポジット"
+ "message": "別のアカウントから入金"
},
"depositShapeShift": {
- "message": "ShapeShiftでデポジット"
+ "message": "ShapeShiftで入金"
},
"depositShapeShiftExplainer": {
- "message": "あなたが他の暗号通貨を持っているなら、Etherにトレードしてダイレクトにメタマスクウォレットへのデポジットが可能です。アカウント作成は不要。"
+ "message": "他の暗号通貨をEtherと交換してMetaMaskのウォレットへ入金できます。アカウント作成は不要です。"
},
"details": {
"message": "詳細"
@@ -176,10 +188,10 @@
"message": "ダイレクトデポジット"
},
"directDepositEther": {
- "message": "Etherをダイレクトデポジット"
+ "message": "Etherを直接受け取り"
},
"directDepositEtherExplainer": {
- "message": "あなたがEtherをすでにお持ちなら、ダイレクトデポジットは新しいウォレットにEtherを入手する最も迅速な方法です。"
+ "message": "Etherをすでにお持ちなら、MetaMaskの新しいウォレットにEtherを送信することができます。"
},
"done": {
"message": "完了"
@@ -197,7 +209,7 @@
"message": "パスワードを入力"
},
"etherscanView": {
- "message": "Etherscanでアカウントを見る"
+ "message": "Etherscanでアカウントを参照"
},
"exchangeRate": {
"message": "交換レート"
@@ -257,7 +269,7 @@
"message": "Etherをゲット"
},
"getEtherFromFaucet": {
- "message": "フォーセットで $1のEtherをゲット",
+ "message": "フォーセットで $1のEtherを得ることができます。",
"description": "Displays network name for Ether faucet"
},
"greaterThanMin": {
@@ -281,12 +293,15 @@
"message": "どのようにEtherをデポジットしますか?"
},
"import": {
- "message": "インポート",
+ "message": "追加",
"description": "Button to import an account from a selected file"
},
"importAccount": {
"message": "アカウントのインポート"
},
+ "importAccountMsg": {
+ "message":"追加したアカウントはMetaMaskのアカウントシードフレーズとは関連付けられません。インポートしたアカウントについての詳細は"
+ },
"importAnAccount": {
"message": "アカウントをインポート"
},
@@ -298,7 +313,10 @@
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
- "message": "インフォメーションとヘルプ"
+ "message": "情報とヘルプ"
+ },
+ "insufficientFunds": {
+ "message": "残高不足"
},
"invalidAddress": {
"message": "アドレスが無効です。"
@@ -354,7 +372,7 @@
"message": "マイアカウント"
},
"needEtherInWallet": {
- "message": "MetaMaskを使って分散型アプリケーションと対話するためには、あなたのウォレットにEtherが必要になります。"
+ "message": "MetaMaskを使って分散型アプリケーションを使用するためには、このウォレットにEtherが必要です。"
},
"needImportFile": {
"message": "インポートするファイルを選択してください。",
@@ -383,6 +401,9 @@
"newRecipient": {
"message": "新規受取人"
},
+ "newRPC": {
+ "message": "新しいRPCのURLを追加"
+ },
"next": {
"message": "次へ"
},
@@ -460,12 +481,21 @@
"rejected": {
"message": "拒否されました"
},
+ "resetAccount": {
+ "message": "アカウントをリセット"
+ },
+ "restoreFromSeed": {
+ "message": "パスフレーズから復元する"
+ },
"required": {
"message": "必要です。"
},
"retryWithMoreGas": {
"message": "より高いガスプライスで再度試して下さい。"
},
+ "revealSeedWords": {
+ "message": "パスフレーズを表示"
+ },
"revert": {
"message": "元に戻す"
},
@@ -495,8 +525,11 @@
"sendTokens": {
"message": "トークンを送る"
},
+ "onlySendToEtherAddress": {
+ "message": "ETHはイーサリウムアカウントのみに送信できます。"
+ },
"sendTokensAnywhere": {
- "message": "イーサリアムのアカウントを持っている人にトークンを送る"
+ "message": "イーサリアムアカウントを持っている人にトークンを送る"
},
"settings": {
"message": "設定"
@@ -544,9 +577,21 @@
"message": "ShapeShiftで $1をETHにする",
"description": "system will fill in deposit type in start of message"
},
+ "tokenAddress": {
+ "message": "トークンアドレス"
+ },
"tokenBalance": {
"message": "あなたのトークン残高:"
},
+ "tokenSelection": {
+ "message": "トークンを検索、またはリストから選択してください。"
+ },
+ "tokenSymbol": {
+ "message": "トークンシンボル"
+ },
+ "tokenWarning1": {
+ "message": "MetaMaskのアカウントで取得したアカウントのみ追加できます。他のアカウントを使用して取得したトークンは、カスタムトークンを使用してください。"
+ },
"total": {
"message": "合計"
},
@@ -591,6 +636,9 @@
"usedByClients": {
"message": "様々なクライアントによって使用されています。"
},
+ "useOldUI": {
+ "message": "旧UIに切り替え"
+ },
"viewAccount": {
"message": "アカウントを見る"
},
diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json
index 90f63c6a6..e39793430 100644
--- a/app/_locales/zh_TW/messages.json
+++ b/app/_locales/zh_TW/messages.json
@@ -171,6 +171,9 @@
"customGas": {
"message": "自訂 Gas"
},
+ "customToken": {
+ "message": "自訂代幣"
+ },
"customize": {
"message": "自訂"
},
@@ -184,7 +187,7 @@
"message": "小數點精度"
},
"defaultNetwork": {
- "message": "預設Ether交易網路為主網(Main Net)。"
+ "message": "預設 Ether 交易網路為主網路(Main Net)。"
},
"denExplainer": {
"message": "你的 DEN 是在你的 MetaMask 中的加密密碼儲存庫。"
@@ -215,7 +218,7 @@
"message": "從 ShapeShift 存入"
},
"depositShapeShiftExplainer": {
- "message": "如果你擁有其他加密貨幣,你可以直接交易並存入 Ether 到你的MetaMask錢包。不需要開帳戶。"
+ "message": "如果你擁有其他加密貨幣,你可以直接交易並存入 Ether 到你的 MetaMask 錢包。不需要開帳戶。"
},
"details": {
"message": "詳情"
@@ -227,7 +230,7 @@
"message": "直接存入 Ether"
},
"directDepositEtherExplainer": {
- "message": "如果你已經擁有了一些Ether,使用直接存入功能是讓你的新錢包最快取得Ether的方式。"
+ "message": "如果你已經擁有了一些 Ether,使用直接存入功能是讓你的新錢包最快取得 Ether 的方式。"
},
"done": {
"message": "完成"
@@ -285,6 +288,9 @@
"message": "檔案導入失敗?點擊這裡!",
"description": "Helps user import their account from a JSON file"
},
+ "followTwitter": {
+ "message": "追蹤 Twitter"
+ },
"from": {
"message": "來源地址"
},
@@ -313,6 +319,9 @@
"gasLimitTooLow": {
"message": "Gas 上限至少為 21000"
},
+ "generatingSeed": {
+ "message": "產生助憶詞中..."
+ },
"gasPrice": {
"message": "Gas 價格 (GWEI)"
},
@@ -362,6 +371,9 @@
"importAccount": {
"message": "導入帳戶"
},
+ "importAccountMsg": {
+ "message":" 匯入的帳戶與您原有 MetaMask 帳戶的助憶詞並無關聯. 請查看與導入帳戶相關的資料 "
+ },
"importAnAccount": {
"message": "導入一個帳戶"
},
@@ -400,12 +412,15 @@
"message": "無效的 RPC URI"
},
"jsonFail": {
- "message": "有東西出錯了. 請確認你的 JSON 檔案格式正確."
+ "message": "有東西出錯了. 請確認你的 JSON 檔案格式正確。"
},
"jsonFile": {
"message": "JSON 檔案",
"description": "format for importing an account"
},
+ "keepTrackTokens": {
+ "message": "持續追蹤您 MetaMask 帳戶中的代幣。"
+ },
"kovan": {
"message": "Kovan 測試網路"
},
@@ -415,6 +430,9 @@
"max": {
"message": "最大值"
},
+ "learnMore": {
+ "message": "了解更多。"
+ },
"lessThanMax": {
"message": "必須小於等於 $1.",
"description": "helper for inputting hex as decimal input"
@@ -437,17 +455,20 @@
"localhost": {
"message": "Localhost 8545"
},
+ "login": {
+ "message": "登入"
+ },
"logout": {
"message": "登出"
},
"loose": {
- "message": "非Metamask帳號"
+ "message": "非 MetaMask 帳號"
},
"loweCaseWords": {
"message": "助憶詞僅包含小寫字元"
},
"mainnet": {
- "message": "主乙太坊網路"
+ "message": "乙太坊 主網路"
},
"message": {
"message": "訊息"
@@ -465,7 +486,7 @@
"message": "必須選擇至少 1 代幣."
},
"needEtherInWallet": {
- "message": "要使用 MetaMask 存取 DAPP時,您的錢包中需要有 Ether。"
+ "message": "要使用 MetaMask 存取 DAPP 時,您的錢包中需要有 Ether。"
},
"needImportFile": {
"message": "您必須選擇一個檔案來導入。",
@@ -475,6 +496,9 @@
"message": "您必須為選擇好的檔案輸入密碼。",
"description": "Password and file needed to import an account"
},
+ "negativeETH": {
+ "message": "不能送出負值的 ETH。"
+ },
"networks": {
"message": "網路"
},
@@ -525,6 +549,9 @@
"message": "或",
"description": "choice between creating or importing a new account"
},
+ "passwordCorrect": {
+ "message": "請確認您的密碼是正確的。"
+ },
"passwordMismatch": {
"message": "密碼不一致",
"description": "in password creation process, the two new password fields did not match"
@@ -546,6 +573,12 @@
"pleaseReviewTransaction": {
"message": "請檢查你的交易。"
},
+ "popularTokens": {
+ "message": "常見的代幣"
+ },
+ "privacyMsg": {
+ "message": "隱私政策"
+ },
"privateKey": {
"message": "私鑰",
"description": "select this type of file to use to import an account"
@@ -681,6 +714,9 @@
"onlySendToEtherAddress": {
"message": "只發送 ETH 到乙太坊地址."
},
+ "searchTokens": {
+ "message": "搜尋代幣"
+ },
"sendTokensAnywhere": {
"message": "發送代幣給擁有乙太坊帳戶的任何人"
},
@@ -700,13 +736,16 @@
"message": "顯示 QR Code"
},
"sign": {
- "message": "簽名"
+ "message": "簽署"
+ },
+ "signed": {
+ "message": "已簽署"
},
"signMessage": {
"message": "簽署訊息"
},
"signNotice": {
- "message": "簽署此訊息可能會產生危險的副作用。 \n只從你完全信任的網站上簽名。這種危險的方法;將在未來的版本中被移除。"
+ "message": "簽署此訊息可能會產生危險地副作用。 \n只從你完全信任的網站上簽署。這種危險的方法;將在未來的版本中被移除。"
},
"sigRequest": {
"message": "請求簽署"
@@ -767,7 +806,7 @@
"message": "代幣餘額:"
},
"tokenSelection": {
- "message": "搜尋代幣或是從熱門代幣列表中選擇。"
+ "message": "搜尋代幣或是從常見代幣列表中選擇。"
},
"tokenSymbol": {
"message": "代幣代號"
@@ -804,7 +843,7 @@
"message": "歡迎使用新版界面 (Beta)"
},
"uiWelcomeMessage": {
- "message": "你現在正在使用新的 Metamask 界面。試試諸如發送代幣等新功能,有任何問題請告知我們。"
+ "message": "你現在正在使用新版 MetaMask 界面。試試諸如發送代幣等新功能吧,有任何問題請告知我們。"
},
"unapproved": {
"message": "未同意"
diff --git a/package-lock.json b/package-lock.json
index 5d1c46c26..d6ada40b0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2994,6 +2994,19 @@
"readdirp": "2.1.0"
}
},
+ "chromedriver": {
+ "version": "2.36.0",
+ "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.36.0.tgz",
+ "integrity": "sha512-Lq2HrigCJ4RVdIdCmchenv1rVrejNSJ7EUCQojycQo12ww3FedQx4nb+GgTdqMhjbOMTqq5+ziaiZlrEN2z1gQ==",
+ "dev": true,
+ "requires": {
+ "del": "3.0.0",
+ "extract-zip": "1.6.6",
+ "kew": "0.7.0",
+ "mkdirp": "0.5.1",
+ "request": "2.83.0"
+ }
+ },
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@@ -6382,6 +6395,35 @@
"is-extglob": "1.0.0"
}
},
+ "extract-zip": {
+ "version": "1.6.6",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz",
+ "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=",
+ "dev": true,
+ "requires": {
+ "concat-stream": "1.6.0",
+ "debug": "2.6.9",
+ "mkdirp": "0.5.0",
+ "yauzl": "2.4.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
+ "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ }
+ }
+ },
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@@ -6490,6 +6532,15 @@
}
}
},
+ "fd-slicer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
+ "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
+ "dev": true,
+ "requires": {
+ "pend": "1.2.0"
+ }
+ },
"fetch-ponyfill": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz",
@@ -11159,6 +11210,53 @@
"array-includes": "3.0.3"
}
},
+ "jszip": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz",
+ "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==",
+ "dev": true,
+ "requires": {
+ "core-js": "2.3.0",
+ "es6-promise": "3.0.2",
+ "lie": "3.1.1",
+ "pako": "1.0.6",
+ "readable-stream": "2.0.6"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz",
+ "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=",
+ "dev": true
+ },
+ "es6-promise": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz",
+ "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
+ "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "string_decoder": "0.10.31",
+ "util-deprecate": "1.0.2"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ }
+ }
+ },
"just-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
@@ -11454,6 +11552,12 @@
"sha3": "1.2.0"
}
},
+ "kew": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz",
+ "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=",
+ "dev": true
+ },
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
@@ -11765,6 +11869,23 @@
"integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=",
"dev": true
},
+ "lie": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
+ "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
+ "dev": true,
+ "requires": {
+ "immediate": "3.0.6"
+ },
+ "dependencies": {
+ "immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=",
+ "dev": true
+ }
+ }
+ },
"liftoff": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
@@ -16369,6 +16490,12 @@
"sha.js": "2.4.9"
}
},
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
"percentile": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/percentile/-/percentile-1.2.0.tgz",
@@ -18331,6 +18458,29 @@
"safe-buffer": "5.1.1"
}
},
+ "selenium-webdriver": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz",
+ "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==",
+ "dev": true,
+ "requires": {
+ "jszip": "3.1.5",
+ "rimraf": "2.6.2",
+ "tmp": "0.0.30",
+ "xml2js": "0.4.19"
+ },
+ "dependencies": {
+ "tmp": {
+ "version": "0.0.30",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
+ "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "1.0.2"
+ }
+ }
+ }
+ },
"semaphore": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz",
@@ -22243,6 +22393,22 @@
"integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
"dev": true
},
+ "xml2js": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+ "dev": true,
+ "requires": {
+ "sax": "1.2.4",
+ "xmlbuilder": "9.0.7"
+ }
+ },
+ "xmlbuilder": {
+ "version": "9.0.7",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
+ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
+ "dev": true
+ },
"xmldom": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",
@@ -22310,6 +22476,15 @@
"camelcase": "3.0.0"
}
},
+ "yauzl": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
+ "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
+ "dev": true,
+ "requires": {
+ "fd-slicer": "1.0.1"
+ }
+ },
"yazl": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/yazl/-/yazl-2.4.3.tgz",
diff --git a/package.json b/package.json
index b43112358..c1ba6e761 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js",
"test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara",
"test:integration:build": "gulp build:scss",
+ "test:e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive",
"test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload",
"test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi",
"test:flat": "npm run test:flat:build && karma start test/flat.conf.js",
@@ -202,6 +203,7 @@
"brfs": "^1.4.3",
"browserify": "^16.1.1",
"chai": "^4.1.0",
+ "chromedriver": "^2.34.1",
"compression": "^1.7.1",
"coveralls": "^3.0.0",
"cross-env": "^5.1.4",
@@ -231,7 +233,7 @@
"gulp-watch": "^5.0.0",
"gulp-zip": "^4.0.0",
"isomorphic-fetch": "^2.2.1",
- "jsdom": "^11.1.0",
+ "jsdom": "^11.2.0",
"jsdom-global": "^3.0.2",
"jshint-stylish": "~2.2.1",
"karma": "^2.0.0",
@@ -254,6 +256,7 @@
"react-addons-test-utils": "^15.5.1",
"react-test-renderer": "^15.6.2",
"react-testutils-additions": "^15.2.0",
+ "selenium-webdriver": "^3.5.0",
"redux-test-utils": "^0.2.2",
"sinon": "^4.0.0",
"stylelint-config-standard": "^18.2.0",
diff --git a/test/e2e/func.js b/test/e2e/func.js
new file mode 100644
index 000000000..733225565
--- /dev/null
+++ b/test/e2e/func.js
@@ -0,0 +1,18 @@
+require('chromedriver')
+const webdriver = require('selenium-webdriver')
+
+exports.delay = function delay (time) {
+ return new Promise(resolve => setTimeout(resolve, time))
+}
+
+
+exports.buildWebDriver = function buildWebDriver (extPath) {
+ return new webdriver.Builder()
+ .withCapabilities({
+ chromeOptions: {
+ args: [`load-extension=${extPath}`],
+ },
+ })
+ .forBrowser('chrome')
+ .build()
+}
diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js
new file mode 100644
index 000000000..c73ba2b41
--- /dev/null
+++ b/test/e2e/metamask.spec.js
@@ -0,0 +1,122 @@
+const path = require('path')
+const assert = require('assert')
+const webdriver = require('selenium-webdriver')
+const By = webdriver.By
+const { delay, buildWebDriver } = require('./func')
+
+describe('Metamask popup page', function () {
+ let driver
+ this.seedPhase
+ this.accountAddress
+ this.timeout(0)
+
+ before(async function () {
+ const extPath = path.resolve('dist/chrome')
+ driver = buildWebDriver(extPath)
+ await driver.get('chrome://extensions-frame')
+ const elems = await driver.findElements(By.className('extension-list-item-wrapper'))
+ const extensionId = await elems[1].getAttribute('id')
+ await driver.get(`chrome-extension://${extensionId}/popup.html`)
+ await delay(500)
+ })
+
+ after(async function () {
+ await driver.quit()
+ })
+
+ describe('#onboarding', () => {
+ it('should open Metamask.io', async function () {
+ const tabs = await driver.getAllWindowHandles()
+ await driver.switchTo().window(tabs[0])
+ await delay(300)
+ })
+
+ it('should match title', async () => {
+ const title = await driver.getTitle()
+ assert.equal(title, 'MetaMask Plugin', 'title matches MetaMask Plugin')
+ })
+
+ it('should show privacy notice', async () => {
+ const privacy = await driver.findElement(By.className(
+ 'terms-header'
+ )).getText()
+ assert.equal(privacy, 'PRIVACY NOTICE', 'shows privacy notice')
+ driver.findElement(By.css(
+ 'button'
+ )).click()
+ })
+
+ it('should show terms of use', async () => {
+ await delay(300)
+ const terms = await driver.findElement(By.className(
+ 'terms-header'
+ )).getText()
+ assert.equal(terms, 'TERMS OF USE', 'shows terms of use')
+ })
+
+ it('should be unable to continue without scolling throught the terms of use', async () => {
+ const button = await driver.findElement(By.css(
+ 'button'
+ )).isEnabled()
+ assert.equal(button, false, 'disabled continue button')
+ const element = driver.findElement(By.linkText(
+ 'Attributions'
+ ))
+ await driver.executeScript('arguments[0].scrollIntoView(true)', element)
+ })
+
+ it('should be able to continue when scrolled to the bottom of terms of use', async () => {
+ const button = await driver.findElement(By.css('button'))
+ const buttonEnabled = await button.isEnabled()
+ await delay(500)
+ assert.equal(buttonEnabled, true, 'enabled continue button')
+ await button.click()
+ })
+
+ it('should accept password with length of eight', async () => {
+ await delay(300)
+ const passwordBox = await driver.findElement(By.id('password-box'))
+ const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm'))
+ const button = driver.findElement(By.css('button'))
+
+ passwordBox.sendKeys('123456789')
+ passwordBoxConfirm.sendKeys('123456789')
+ await delay(500)
+ await button.click()
+ })
+
+ it('should show value was created and seed phrase', async () => {
+ await delay(700)
+ this.seedPhase = await driver.findElement(By.className('twelve-word-phrase')).getText()
+ const continueAfterSeedPhrase = await driver.findElement(By.css('button'))
+ await continueAfterSeedPhrase.click()
+ })
+
+ it('should show lock account', async () => {
+ await delay(300)
+ await driver.findElement(By.className('sandwich-expando')).click()
+ await delay(500)
+ await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[3]/span/div/li[2]')).click()
+ })
+
+ it('should accept account password after lock', async () => {
+ await delay(500)
+ await driver.findElement(By.id('password-box')).sendKeys('123456789')
+ await driver.findElement(By.css('button')).click()
+ await delay(500)
+ })
+
+ it('should show QR code', async () => {
+ await delay(300)
+ await driver.findElement(By.className('fa-ellipsis-h')).click()
+ await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[4]/div/div/div[1]/flex-column/div[1]/div/span/i/div/div/li[2]')).click()
+ await delay(300)
+ })
+
+ it('should show the account address', async () => {
+ this.accountAddress = await driver.findElement(By.className('ellip-address')).getText()
+ await driver.findElement(By.className('fa-arrow-left')).click()
+ await delay(500)
+ })
+ })
+})