spec: add new test runner for main-process based tests (#17325)

This commit is contained in:
Samuel Attard 2019-03-17 14:49:00 -07:00 committed by GitHub
commit 108545e416
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 681 additions and 334 deletions

View file

@ -810,7 +810,13 @@ steps-tests: &steps-tests
- run:
name: Check test results existence
command: |
MOCHA_FILE='src/junit/test-results.xml'
MOCHA_FILE='src/junit/test-results-remote.xml'
# Check if it exists and not empty.
if [ ! -s "$MOCHA_FILE" ]; then
exit 1
fi
MOCHA_FILE='src/junit/test-results-main.xml'
# Check if it exists and not empty.
if [ ! -s "$MOCHA_FILE" ]; then
exit 1

269
package-lock.json generated
View file

@ -155,12 +155,52 @@
"any-observable": "^0.3.0"
}
},
"@types/chai": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz",
"integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==",
"dev": true
},
"@types/chai-as-promised": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.0.tgz",
"integrity": "sha512-MFiW54UOSt+f2bRw8J7LgQeIvE/9b4oGvwU7XW30S9QGAiHGnU/fmiOprsyMkdmH2rl8xSPc0/yrQw8juXU6bQ==",
"dev": true,
"requires": {
"@types/chai": "*"
}
},
"@types/mocha": {
"version": "5.2.6",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz",
"integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==",
"dev": true
},
"@types/node": {
"version": "10.12.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.21.tgz",
"integrity": "sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ==",
"dev": true
},
"@types/split": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/split/-/split-1.0.0.tgz",
"integrity": "sha512-pm9S1mkr+av0j7D6pFyqhBxXDbnbO9gqj4nb8DtGtCewvj0XhIv089SSwXrjrIizT1UquO8/h83hCut0pa3u8A==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/through": "*"
}
},
"@types/through": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.29.tgz",
"integrity": "sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@typescript-eslint/eslint-plugin": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.4.2.tgz",
@ -4677,28 +4717,27 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
"resolved": false,
"resolved": "",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
"resolved": false,
"resolved": "",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
"resolved": false,
"resolved": "",
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
"dev": true,
"optional": true,
@ -4709,17 +4748,15 @@
},
"balanced-match": {
"version": "1.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": false,
"resolved": "",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -4727,42 +4764,39 @@
},
"chownr": {
"version": "1.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"debug": {
"version": "2.6.9",
"resolved": false,
"resolved": "",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
@ -4772,28 +4806,28 @@
},
"deep-extend": {
"version": "0.5.1",
"resolved": false,
"resolved": "",
"integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"resolved": false,
"resolved": "",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
"resolved": false,
"resolved": "",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"dev": true,
"optional": true,
@ -4803,14 +4837,14 @@
},
"fs.realpath": {
"version": "1.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"resolved": false,
"resolved": "",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
@ -4827,7 +4861,7 @@
},
"glob": {
"version": "7.1.2",
"resolved": false,
"resolved": "",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"optional": true,
@ -4842,14 +4876,14 @@
},
"has-unicode": {
"version": "2.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.21",
"resolved": false,
"resolved": "",
"integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
"dev": true,
"optional": true,
@ -4859,7 +4893,7 @@
},
"ignore-walk": {
"version": "3.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true,
"optional": true,
@ -4869,7 +4903,7 @@
},
"inflight": {
"version": "1.0.6",
"resolved": false,
"resolved": "",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"optional": true,
@ -4880,58 +4914,53 @@
},
"inherits": {
"version": "2.0.3",
"resolved": false,
"resolved": "",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
"resolved": false,
"resolved": "",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"resolved": false,
"resolved": "",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"resolved": false,
"resolved": "",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.2.4",
"resolved": false,
"resolved": "",
"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@ -4939,7 +4968,7 @@
},
"minizlib": {
"version": "1.1.0",
"resolved": false,
"resolved": "",
"integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
"dev": true,
"optional": true,
@ -4949,24 +4978,23 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true,
"optional": true
},
"needle": {
"version": "2.2.0",
"resolved": false,
"resolved": "",
"integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
"dev": true,
"optional": true,
@ -4978,7 +5006,7 @@
},
"node-pre-gyp": {
"version": "0.10.0",
"resolved": false,
"resolved": "",
"integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==",
"dev": true,
"optional": true,
@ -4997,7 +5025,7 @@
},
"nopt": {
"version": "4.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
@ -5008,14 +5036,14 @@
},
"npm-bundled": {
"version": "1.0.3",
"resolved": false,
"resolved": "",
"integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.10",
"resolved": false,
"resolved": "",
"integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
"dev": true,
"optional": true,
@ -5026,7 +5054,7 @@
},
"npmlog": {
"version": "4.1.2",
"resolved": false,
"resolved": "",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
@ -5039,45 +5067,43 @@
},
"number-is-nan": {
"version": "1.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"resolved": false,
"resolved": "",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"optional": true,
@ -5088,21 +5114,21 @@
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.7",
"resolved": false,
"resolved": "",
"integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==",
"dev": true,
"optional": true,
@ -5115,7 +5141,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
@ -5124,7 +5150,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": false,
"resolved": "",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
@ -5140,7 +5166,7 @@
},
"rimraf": {
"version": "2.6.2",
"resolved": false,
"resolved": "",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"optional": true,
@ -5150,52 +5176,50 @@
},
"safe-buffer": {
"version": "5.1.1",
"resolved": false,
"resolved": "",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
"resolved": false,
"resolved": "",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"resolved": false,
"resolved": "",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.5.0",
"resolved": false,
"resolved": "",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"resolved": false,
"resolved": "",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -5204,7 +5228,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": false,
"resolved": "",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
@ -5214,24 +5238,23 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": false,
"resolved": "",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.1",
"resolved": false,
"resolved": "",
"integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==",
"dev": true,
"optional": true,
@ -5247,14 +5270,14 @@
},
"util-deprecate": {
"version": "1.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.2",
"resolved": false,
"resolved": "",
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
"dev": true,
"optional": true,
@ -5264,17 +5287,15 @@
},
"wrappy": {
"version": "1.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.2",
"resolved": false,
"resolved": "",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"dev": true,
"optional": true
"dev": true
}
}
},
@ -7787,6 +7808,12 @@
}
}
},
"make-error": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
"dev": true
},
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@ -11197,6 +11224,24 @@
"urix": "^0.1.0"
}
},
"source-map-support": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz",
"integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"source-map-url": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
@ -12584,6 +12629,30 @@
"integrity": "sha512-FHkoUZvG6Egrv9XZAyYGKEyb1JMsFphgPjoczkZC2y6W93U1jswcVURB8MUvtsahEPEVACyxD47JAL63vF4JsQ==",
"dev": true
},
"ts-node": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-6.2.0.tgz",
"integrity": "sha512-ZNT+OEGfUNVMGkpIaDJJ44Zq3Yr0bkU/ugN1PHbU+/01Z7UV1fsELRiTx1KuQNvQ1A3pGh3y25iYF6jXgxV21A==",
"dev": true,
"requires": {
"arrify": "^1.0.0",
"buffer-from": "^1.1.0",
"diff": "^3.1.0",
"make-error": "^1.1.1",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"source-map-support": "^0.5.6",
"yn": "^2.0.0"
},
"dependencies": {
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
}
}
},
"tsconfig": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz",
@ -13614,6 +13683,12 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"dev": true
},
"yn": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
"integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=",
"dev": true
}
}
}
}

View file

@ -5,7 +5,11 @@
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
"@octokit/rest": "^16.3.2",
"@types/chai": "^4.1.7",
"@types/chai-as-promised": "^7.1.0",
"@types/mocha": "^5.2.6",
"@types/node": "^10.12.21",
"@types/split": "^1.0.0",
"@typescript-eslint/eslint-plugin": "^1.4.2",
"@typescript-eslint/parser": "^1.4.2",
"aliasify": "^2.1.0",
@ -42,6 +46,7 @@
"standard-markdown": "^5.0.0",
"sumchecker": "^2.0.2",
"temp": "^0.8.3",
"ts-node": "^6.0.3",
"tsify": "^4.0.1",
"typescript": "~3.3.3333"
},
@ -71,7 +76,7 @@
"prepush": "check-for-leaks",
"repl": "node ./script/start.js --interactive",
"start": "node ./script/start.js",
"test": "node ./script/spec-runner.js electron/spec",
"test": "node ./script/spec-runner.js",
"tsc": "tsc"
},
"license": "MIT",
@ -115,4 +120,4 @@
"git add filenames.auto.gni"
]
}
}
}

View file

@ -5,6 +5,12 @@ const crypto = require('crypto')
const fs = require('fs')
const { hashElement } = require('folder-hash')
const path = require('path')
const unknownArgs = []
const args = require('minimist')(process.argv, {
string: ['runners'],
unknown: arg => unknownArgs.push(arg)
})
const utils = require('./lib/utils')
@ -13,6 +19,14 @@ const NPM_CMD = process.platform === 'win32' ? 'npm.cmd' : 'npm'
const specHashPath = path.resolve(__dirname, '../spec/.hash')
let runnersToRun = null
if (args.runners) {
runnersToRun = args.runners.split(',')
console.log('Only running:', runnersToRun)
} else {
console.log('Will trigger all spec runners')
}
async function main () {
const [lastSpecHash, lastSpecInstallHash] = loadLastSpecHash()
const [currentSpecHash, currentSpecInstallHash] = await getSpecHash()
@ -24,9 +38,24 @@ async function main () {
await getSpecHash().then(saveSpecHash)
}
if (!fs.existsSync(path.resolve(__dirname, '../electron.d.ts'))) {
console.log('Generating electron.d.ts as it is missing')
generateTypeDefinitions()
}
await runElectronTests()
}
function generateTypeDefinitions () {
const { status } = childProcess.spawnSync('npm', ['run', 'create-typescript-definitions'], {
cwd: path.resolve(__dirname, '..'),
stdio: 'inherit'
})
if (status !== 0) {
throw new Error(`Electron typescript definition generation failed with exit code: ${status}.`)
}
}
function loadLastSpecHash () {
return fs.existsSync(specHashPath)
? fs.readFileSync(specHashPath, 'utf8').split('\n')
@ -38,14 +67,59 @@ function saveSpecHash ([newSpecHash, newSpecInstallHash]) {
}
async function runElectronTests () {
const errors = []
const runners = [
['Remote based specs', 'remote', runRemoteBasedElectronTests],
['Main process specs', 'main', runMainProcessElectronTests]
]
const mochaFile = process.env.MOCHA_FILE
for (const runner of runners) {
if (runnersToRun && !runnersToRun.includes(runner[1])) {
console.info('\nSkipping:', runner[0])
continue
}
try {
console.info('\nRunning:', runner[0])
if (mochaFile) {
process.env.MOCHA_FILE = mochaFile.replace('.xml', `-${runner[1]}.xml`)
}
await runner[2]()
} catch (err) {
errors.push([runner[0], err])
}
}
if (errors.length !== 0) {
for (const err of errors) {
console.error('\n\nRunner Failed:', err[0])
console.error(err[1])
}
throw new Error('Electron test runners have failed')
}
}
async function runRemoteBasedElectronTests () {
let exe = path.resolve(BASE, utils.getElectronExec())
const args = process.argv.slice(2)
const runnerArgs = ['electron/spec', ...unknownArgs.slice(2)]
if (process.platform === 'linux') {
args.unshift(path.resolve(__dirname, 'dbus_mock.py'), exe)
runnerArgs.unshift(path.resolve(__dirname, 'dbus_mock.py'), exe)
exe = 'python'
}
const { status } = childProcess.spawnSync(exe, args, {
const { status } = childProcess.spawnSync(exe, runnerArgs, {
cwd: path.resolve(__dirname, '../..'),
stdio: 'inherit'
})
if (status !== 0) {
throw new Error(`Electron tests failed with code ${status}.`)
}
}
async function runMainProcessElectronTests () {
const exe = path.resolve(BASE, utils.getElectronExec())
const { status } = childProcess.spawnSync(exe, ['electron/spec-main', ...unknownArgs.slice(2)], {
cwd: path.resolve(__dirname, '../..'),
stdio: 'inherit'
})

20
spec-main/.eslintrc Normal file
View file

@ -0,0 +1,20 @@
{
"env": {
"browser": true,
"mocha": true,
"jquery": true,
"serviceworker": true
},
"globals": {
"Bindings": true,
"Components": true,
"UI": true,
"WebView": true
},
"plugins": [
"mocha"
],
"rules": {
"mocha/no-exclusive-tests": "error"
}
}

1
spec-main/ambient.d.ts vendored Normal file
View file

@ -0,0 +1 @@
declare var isCI: boolean;

View file

@ -1,24 +1,20 @@
const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')
const dirtyChai = require('dirty-chai')
const ChildProcess = require('child_process')
const https = require('https')
const net = require('net')
const fs = require('fs')
const path = require('path')
const cp = require('child_process')
const split = require('split')
const { ipcRenderer, remote } = require('electron')
const { emittedOnce } = require('./events-helpers')
const { closeWindow } = require('./window-helpers')
import * as chai from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
import * as cp from 'child_process'
import * as https from 'https'
import * as net from 'net'
import * as fs from 'fs'
import * as path from 'path'
import split = require('split')
import { app, BrowserWindow, Menu } from 'electron'
import { emittedOnce } from './events-helpers';
import { closeWindow } from './window-helpers';
const { expect } = chai
const { app, BrowserWindow, Menu, ipcMain } = remote
const isCI = remote.getGlobal('isCi')
chai.use(chaiAsPromised)
chai.use(dirtyChai)
const fixturesPath = path.resolve(__dirname, '../spec/fixtures')
describe('electron module', () => {
it('does not expose internal modules to require', () => {
@ -28,33 +24,16 @@ describe('electron module', () => {
})
describe('require("electron")', () => {
let window = null
beforeEach(() => {
window = new BrowserWindow({
show: false,
width: 400,
height: 400,
webPreferences: {
nodeIntegration: true
}
})
})
afterEach(() => {
return closeWindow(window).then(() => { window = null })
})
it('always returns the internal electron module', (done) => {
ipcMain.once('answer', () => done())
window.loadFile(path.join(__dirname, 'fixtures', 'api', 'electron-module-app', 'index.html'))
it('always returns the internal electron module', () => {
require('electron')
})
})
})
describe('app module', () => {
let server, secureUrl
const certPath = path.join(__dirname, 'fixtures', 'certificates')
let server: https.Server
let secureUrl: string
const certPath = path.join(fixturesPath, 'certificates')
before((done) => {
const options = {
@ -69,7 +48,7 @@ describe('app module', () => {
}
server = https.createServer(options, (req, res) => {
if (req.client.authorized) {
if ((req as any).client.authorized) {
res.writeHead(200)
res.end('<title>authorized</title>')
} else {
@ -79,7 +58,7 @@ describe('app module', () => {
})
server.listen(0, '127.0.0.1', () => {
const port = server.address().port
const port = (server.address() as net.AddressInfo).port
secureUrl = `https://127.0.0.1:${port}`
done()
})
@ -107,13 +86,13 @@ describe('app module', () => {
describe('app.getName()', () => {
it('returns the name field of package.json', () => {
expect(app.getName()).to.equal('Electron Test')
expect(app.getName()).to.equal('Electron Test Main')
})
})
describe('app.setName(name)', () => {
it('overrides the name', () => {
expect(app.getName()).to.equal('Electron Test')
expect(app.getName()).to.equal('Electron Test Main')
app.setName('test-name')
expect(app.getName()).to.equal('test-name')
@ -123,7 +102,7 @@ describe('app module', () => {
describe('app.getLocale()', () => {
it('should not be empty', () => {
expect(app.getLocale()).to.not.be.empty()
expect(app.getLocale()).to.not.equal('')
})
})
@ -140,7 +119,7 @@ describe('app module', () => {
describe('app.isPackaged', () => {
it('should be false durings tests', () => {
expect(app.isPackaged).to.be.false()
expect(app.isPackaged).to.equal(false)
})
})
@ -152,23 +131,23 @@ describe('app module', () => {
})
it('should be false during tests', () => {
expect(app.isInApplicationsFolder()).to.be.false()
expect(app.isInApplicationsFolder()).to.equal(false)
})
})
describe('app.exit(exitCode)', () => {
let appProcess = null
let appProcess: cp.ChildProcess | null = null
afterEach(() => {
if (appProcess != null) appProcess.kill()
if (appProcess) appProcess.kill()
})
it('emits a process exit event with the code', async () => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
const electronPath = remote.getGlobal('process').execPath
const appPath = path.join(fixturesPath, 'api', 'quit-app')
const electronPath = process.execPath
let output = ''
appProcess = ChildProcess.spawn(electronPath, [appPath])
appProcess = cp.spawn(electronPath, [appPath])
appProcess.stdout.on('data', data => { output += data })
const [code] = await emittedOnce(appProcess, 'close')
@ -179,10 +158,10 @@ describe('app module', () => {
})
it('closes all windows', async function () {
const appPath = path.join(__dirname, 'fixtures', 'api', 'exit-closes-all-windows-app')
const electronPath = remote.getGlobal('process').execPath
const appPath = path.join(fixturesPath, 'api', 'exit-closes-all-windows-app')
const electronPath = process.execPath
appProcess = ChildProcess.spawn(electronPath, [appPath])
appProcess = cp.spawn(electronPath, [appPath])
const [code, signal] = await emittedOnce(appProcess, 'close')
expect(signal).to.equal(null, 'exit signal should be null, if you see this please tag @MarshallOfSound')
@ -195,32 +174,32 @@ describe('app module', () => {
return
}
const electronPath = remote.getGlobal('process').execPath
const appPath = path.join(__dirname, 'fixtures', 'api', 'singleton')
appProcess = ChildProcess.spawn(electronPath, [appPath])
const electronPath = process.execPath
const appPath = path.join(fixturesPath, 'api', 'singleton')
appProcess = cp.spawn(electronPath, [appPath])
// Singleton will send us greeting data to let us know it's running.
// After that, ask it to exit gracefully and confirm that it does.
appProcess.stdout.on('data', data => appProcess.kill())
appProcess.stdout.on('data', data => appProcess!.kill())
const [code, signal] = await emittedOnce(appProcess, 'close')
const message = `code:\n${code}\nsignal:\n${signal}`
expect(code).to.equal(0, message)
expect(signal).to.be.null(message)
expect(signal).to.equal(null, message)
})
})
describe('app.requestSingleInstanceLock', () => {
it('prevents the second launch of app', function (done) {
this.timeout(120000)
const appPath = path.join(__dirname, 'fixtures', 'api', 'singleton')
const first = ChildProcess.spawn(remote.process.execPath, [appPath])
const appPath = path.join(fixturesPath, 'api', 'singleton')
const first = cp.spawn(process.execPath, [appPath])
first.once('exit', code => {
expect(code).to.equal(0)
})
// Start second app when received output.
first.stdout.once('data', () => {
const second = ChildProcess.spawn(remote.process.execPath, [appPath])
const second = cp.spawn(process.execPath, [appPath])
second.once('exit', code => {
expect(code).to.equal(1)
done()
@ -229,8 +208,8 @@ describe('app module', () => {
})
it('passes arguments to the second-instance event', async () => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'singleton')
const first = ChildProcess.spawn(remote.process.execPath, [appPath])
const appPath = path.join(fixturesPath, 'api', 'singleton')
const first = cp.spawn(process.execPath, [appPath])
const firstExited = emittedOnce(first, 'exit')
// Wait for the first app to boot.
@ -240,16 +219,16 @@ describe('app module', () => {
}
const data2Promise = emittedOnce(firstStdoutLines, 'data')
const secondInstanceArgs = [remote.process.execPath, appPath, '--some-switch', 'some-arg']
const second = ChildProcess.spawn(secondInstanceArgs[0], secondInstanceArgs.slice(1))
const secondInstanceArgs = [process.execPath, appPath, '--some-switch', 'some-arg']
const second = cp.spawn(secondInstanceArgs[0], secondInstanceArgs.slice(1))
const [code2] = await emittedOnce(second, 'exit')
expect(code2).to.equal(1)
const [code1] = await firstExited
expect(code1).to.equal(0)
const data2 = (await data2Promise).toString('ascii')
const secondInstanceArgsReceived = JSON.parse(data2.toString('ascii'))
const data2 = (await data2Promise)[0].toString('ascii')
const secondInstanceArgsReceived: string[] = JSON.parse(data2.toString('ascii'))
const expected = process.platform === 'win32'
? [remote.process.execPath, '--some-switch', '--allow-file-access-from-files', secondInstanceArgsReceived.find(x => x.includes('original-process-start-time')), appPath, 'some-arg']
? [process.execPath, '--some-switch', '--allow-file-access-from-files', secondInstanceArgsReceived.find(x => x.includes('original-process-start-time')), appPath, 'some-arg']
: secondInstanceArgs
expect(secondInstanceArgsReceived).to.eql(expected,
`expected ${JSON.stringify(expected)} but got ${data2.toString('ascii')}`)
@ -257,7 +236,7 @@ describe('app module', () => {
})
describe('app.relaunch', () => {
let server = null
let server: net.Server | null = null
const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-app-relaunch' : '/tmp/electron-app-relaunch'
beforeEach(done => {
@ -269,7 +248,7 @@ describe('app module', () => {
})
afterEach((done) => {
server.close(() => {
server!.close(() => {
if (process.platform === 'win32') {
done()
} else {
@ -282,8 +261,8 @@ describe('app module', () => {
this.timeout(120000)
let state = 'none'
server.once('error', error => done(error))
server.on('connection', client => {
server!.once('error', error => done(error))
server!.on('connection', client => {
client.once('data', data => {
if (String(data) === 'false' && state === 'none') {
state = 'first-launch'
@ -295,8 +274,8 @@ describe('app module', () => {
})
})
const appPath = path.join(__dirname, 'fixtures', 'api', 'relaunch')
ChildProcess.spawn(remote.process.execPath, [appPath])
const appPath = path.join(fixturesPath, 'api', 'relaunch')
cp.spawn(process.execPath, [appPath])
})
})
@ -313,61 +292,61 @@ describe('app module', () => {
})
})
xdescribe('app.importCertificate', () => {
let w = null
// xdescribe('app.importCertificate', () => {
// let w = null
before(function () {
if (process.platform !== 'linux') {
this.skip()
}
})
// before(function () {
// if (process.platform !== 'linux') {
// this.skip()
// }
// })
afterEach(() => closeWindow(w).then(() => { w = null }))
// afterEach(() => closeWindow(w).then(() => { w = null }))
it('can import certificate into platform cert store', done => {
const options = {
certificate: path.join(certPath, 'client.p12'),
password: 'electron'
}
// it('can import certificate into platform cert store', done => {
// const options = {
// certificate: path.join(certPath, 'client.p12'),
// password: 'electron'
// }
w = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true
}
})
// w = new BrowserWindow({
// show: false,
// webPreferences: {
// nodeIntegration: true
// }
// })
w.webContents.on('did-finish-load', () => {
expect(w.webContents.getTitle()).to.equal('authorized')
done()
})
// w.webContents.on('did-finish-load', () => {
// expect(w.webContents.getTitle()).to.equal('authorized')
// done()
// })
ipcRenderer.once('select-client-certificate', (event, webContentsId, list) => {
expect(webContentsId).to.equal(w.webContents.id)
expect(list).to.have.lengthOf(1)
// ipcRenderer.once('select-client-certificate', (event, webContentsId, list) => {
// expect(webContentsId).to.equal(w.webContents.id)
// expect(list).to.have.lengthOf(1)
expect(list[0]).to.deep.equal({
issuerName: 'Intermediate CA',
subjectName: 'Client Cert',
issuer: { commonName: 'Intermediate CA' },
subject: { commonName: 'Client Cert' }
})
// expect(list[0]).to.deep.equal({
// issuerName: 'Intermediate CA',
// subjectName: 'Client Cert',
// issuer: { commonName: 'Intermediate CA' },
// subject: { commonName: 'Client Cert' }
// })
event.sender.send('client-certificate-response', list[0])
})
// event.sender.send('client-certificate-response', list[0])
// })
app.importCertificate(options, result => {
expect(result).toNotExist()
ipcRenderer.sendSync('set-client-certificate-option', false)
w.loadURL(secureUrl)
})
})
})
// app.importCertificate(options, result => {
// expect(result).toNotExist()
// ipcRenderer.sendSync('set-client-certificate-option', false)
// w.loadURL(secureUrl)
// })
// })
// })
describe('BrowserWindow events', () => {
let w = null
let w: BrowserWindow = null as any
afterEach(() => closeWindow(w).then(() => { w = null }))
afterEach(() => closeWindow(w).then(() => { w = null as any }))
it('should emit browser-window-focus event when window is focused', (done) => {
app.once('browser-window-focus', (e, window) => {
@ -530,7 +509,7 @@ describe('app module', () => {
const platformIsSupported = !platformIsNotSupported
const expectedBadgeCount = 42
let returnValue = null
let returnValue: boolean | null = null
beforeEach(() => { returnValue = app.setBadgeCount(expectedBadgeCount) })
@ -547,7 +526,7 @@ describe('app module', () => {
})
it('returns true', () => {
expect(returnValue).to.be.true()
expect(returnValue).to.equal(true)
})
it('sets a badge count', () => {
@ -563,7 +542,7 @@ describe('app module', () => {
})
it('returns false', () => {
expect(returnValue).to.be.false()
expect(returnValue).to.equal(false)
})
it('does not set a badge count', () => {
@ -618,28 +597,28 @@ describe('app module', () => {
})
it('correctly sets and unsets the LoginItem', function () {
expect(app.getLoginItemSettings().openAtLogin).to.be.false()
expect(app.getLoginItemSettings().openAtLogin).to.equal(false)
app.setLoginItemSettings({ openAtLogin: true })
expect(app.getLoginItemSettings().openAtLogin).to.be.true()
expect(app.getLoginItemSettings().openAtLogin).to.equal(true)
app.setLoginItemSettings({ openAtLogin: false })
expect(app.getLoginItemSettings().openAtLogin).to.be.false()
expect(app.getLoginItemSettings().openAtLogin).to.equal(false)
})
it('correctly sets and unsets the LoginItem as hidden', function () {
if (process.platform !== 'darwin') this.skip()
expect(app.getLoginItemSettings().openAtLogin).to.be.false()
expect(app.getLoginItemSettings().openAsHidden).to.be.false()
expect(app.getLoginItemSettings().openAtLogin).to.equal(false)
expect(app.getLoginItemSettings().openAsHidden).to.equal(false)
app.setLoginItemSettings({ openAtLogin: true, openAsHidden: true })
expect(app.getLoginItemSettings().openAtLogin).to.be.true()
expect(app.getLoginItemSettings().openAsHidden).to.be.true()
expect(app.getLoginItemSettings().openAtLogin).to.equal(true)
expect(app.getLoginItemSettings().openAsHidden).to.equal(true)
app.setLoginItemSettings({ openAtLogin: true, openAsHidden: false })
expect(app.getLoginItemSettings().openAtLogin).to.be.true()
expect(app.getLoginItemSettings().openAsHidden).to.be.false()
expect(app.getLoginItemSettings().openAtLogin).to.equal(true)
expect(app.getLoginItemSettings().openAsHidden).to.equal(false)
})
it('allows you to pass a custom executable and arguments', function () {
@ -647,11 +626,11 @@ describe('app module', () => {
app.setLoginItemSettings({ openAtLogin: true, path: updateExe, args: processStartArgs })
expect(app.getLoginItemSettings().openAtLogin).to.be.false()
expect(app.getLoginItemSettings().openAtLogin).to.equal(false)
expect(app.getLoginItemSettings({
path: updateExe,
args: processStartArgs
}).openAtLogin).to.be.true()
}).openAtLogin).to.equal(true)
})
})
@ -684,7 +663,7 @@ describe('app module', () => {
})
describe('select-client-certificate event', () => {
let w = null
let w: BrowserWindow
before(function () {
if (process.platform === 'linux') {
@ -702,16 +681,16 @@ describe('app module', () => {
})
})
afterEach(() => closeWindow(w).then(() => { w = null }))
afterEach(() => closeWindow(w).then(() => { w = null as any }))
it('can respond with empty certificate list', done => {
w.webContents.on('did-finish-load', () => {
expect(w.webContents.getTitle()).to.equal('denied')
done()
it('can respond with empty certificate list', async () => {
app.once('select-client-certificate', function (event, webContents, url, list, callback) {
console.log('select-client-certificate emitted')
event.preventDefault()
callback()
})
ipcRenderer.sendSync('set-client-certificate-option', true)
w.webContents.loadURL(secureUrl)
await w.webContents.loadURL(secureUrl)
expect(w.webContents.getTitle()).to.equal('denied')
})
})
@ -723,8 +702,8 @@ describe('app module', () => {
'--process-start-args', `"--hidden"`
]
let Winreg
let classesKey
let Winreg: any
let classesKey: any
before(function () {
if (process.platform !== 'win32') {
@ -761,34 +740,34 @@ describe('app module', () => {
afterEach(() => {
app.removeAsDefaultProtocolClient(protocol)
expect(app.isDefaultProtocolClient(protocol)).to.be.false()
expect(app.isDefaultProtocolClient(protocol)).to.equal(false)
app.removeAsDefaultProtocolClient(protocol, updateExe, processStartArgs)
expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.be.false()
expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(false)
})
it('sets the app as the default protocol client', () => {
expect(app.isDefaultProtocolClient(protocol)).to.be.false()
expect(app.isDefaultProtocolClient(protocol)).to.equal(false)
app.setAsDefaultProtocolClient(protocol)
expect(app.isDefaultProtocolClient(protocol)).to.be.true()
expect(app.isDefaultProtocolClient(protocol)).to.equal(true)
})
it('allows a custom path and args to be specified', () => {
expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.be.false()
expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(false)
app.setAsDefaultProtocolClient(protocol, updateExe, processStartArgs)
expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.be.true()
expect(app.isDefaultProtocolClient(protocol)).to.be.false()
expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(true)
expect(app.isDefaultProtocolClient(protocol)).to.equal(false)
})
it('creates a registry entry for the protocol class', (done) => {
app.setAsDefaultProtocolClient(protocol)
classesKey.keys((error, keys) => {
classesKey.keys((error: Error, keys: any[]) => {
if (error) throw error
const exists = !!keys.find(key => key.key.includes(protocol))
expect(exists).to.be.true()
expect(exists).to.equal(true)
done()
})
@ -798,11 +777,11 @@ describe('app module', () => {
app.setAsDefaultProtocolClient(protocol)
app.removeAsDefaultProtocolClient(protocol)
classesKey.keys((error, keys) => {
classesKey.keys((error: Error, keys: any[]) => {
if (error) throw error
const exists = !!keys.find(key => key.key.includes(protocol))
expect(exists).to.be.false()
expect(exists).to.equal(false)
done()
})
@ -819,11 +798,11 @@ describe('app module', () => {
protocolKey.set('test-value', 'REG_BINARY', '123', () => {
app.removeAsDefaultProtocolClient(protocol)
classesKey.keys((error, keys) => {
classesKey.keys((error: Error, keys: any[]) => {
if (error) throw error
const exists = !!keys.find(key => key.key.includes(protocol))
expect(exists).to.be.true()
expect(exists).to.equal(true)
done()
})
@ -839,9 +818,9 @@ describe('app module', () => {
})
it('does not launch for argument following a URL', done => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
const appPath = path.join(fixturesPath, 'api', 'quit-app')
// App should exit with non 123 code.
const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'electron-test:?', 'abc'])
const first = cp.spawn(process.execPath, [appPath, 'electron-test:?', 'abc'])
first.once('exit', code => {
expect(code).to.not.equal(123)
done()
@ -849,9 +828,9 @@ describe('app module', () => {
})
it('launches successfully for argument following a file path', done => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
const appPath = path.join(fixturesPath, 'api', 'quit-app')
// App should exit with code 123.
const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'e:\\abc', 'abc'])
const first = cp.spawn(process.execPath, [appPath, 'e:\\abc', 'abc'])
first.once('exit', code => {
expect(code).to.equal(123)
done()
@ -859,9 +838,9 @@ describe('app module', () => {
})
it('launches successfully for multiple URIs following --', done => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
const appPath = path.join(fixturesPath, 'api', 'quit-app')
// App should exit with code 123.
const first = ChildProcess.spawn(remote.process.execPath, [appPath, '--', 'http://electronjs.org', 'electron-test://testdata'])
const first = cp.spawn(process.execPath, [appPath, '--', 'http://electronjs.org', 'electron-test://testdata'])
first.once('exit', code => {
expect(code).to.equal(123)
done()
@ -869,7 +848,7 @@ describe('app module', () => {
})
})
describe('getFileIcon() API', (done) => {
describe('getFileIcon() API', () => {
const iconPath = path.join(__dirname, 'fixtures/assets/icon.ico')
const sizes = {
small: 16,
@ -888,13 +867,14 @@ describe('app module', () => {
it('fetches a non-empty icon', async () => {
const icon = await app.getFileIcon(iconPath)
expect(icon.isEmpty()).to.be.false()
expect(icon.isEmpty()).to.equal(false)
})
// TODO(codebytere): remove when promisification is complete
it('fetches a non-empty icon (callback)', (done) => {
app.getFileIcon(iconPath, (icon) => {
expect(icon.isEmpty()).to.be.false()
app.getFileIcon(iconPath, (error, icon) => {
expect(error).to.equal(null)
expect(icon.isEmpty()).to.equal(false)
done()
})
})
@ -909,7 +889,8 @@ describe('app module', () => {
// TODO(codebytere): remove when promisification is complete
it('fetches normal icon size by default (callback)', (done) => {
app.getFileIcon(iconPath, (icon) => {
app.getFileIcon(iconPath, (error, icon) => {
expect(error).to.equal(null)
const size = icon.getSize()
expect(size.height).to.equal(sizes.normal)
@ -937,7 +918,8 @@ describe('app module', () => {
// TODO(codebytere): remove when promisification is complete
it('fetches a normal icon (callback)', (done) => {
app.getFileIcon(iconPath, { size: 'normal' }, (icon) => {
app.getFileIcon(iconPath, { size: 'normal' }, (error, icon) => {
expect(error).to.equal(null)
const size = icon.getSize()
expect(size.height).to.equal(sizes.normal)
@ -967,11 +949,11 @@ describe('app module', () => {
const types = []
for (const { pid, type, cpu } of appMetrics) {
expect(pid).to.be.above(0, 'pid is not > 0')
expect(type).to.be.a('string').that.is.not.empty()
expect(type).to.be.a('string').that.does.not.equal('')
types.push(type)
expect(cpu).to.have.own.property('percentCPUUsage').that.is.a('number')
expect(cpu).to.have.own.property('idleWakeupsPerSecond').that.is.a('number')
expect(cpu).to.have.ownProperty('percentCPUUsage').that.is.a('number')
expect(cpu).to.have.ownProperty('idleWakeupsPerSecond').that.is.a('number')
}
if (process.platform === 'darwin') {
@ -979,23 +961,22 @@ describe('app module', () => {
}
expect(types).to.include('Browser')
expect(types).to.include('Tab')
})
})
describe('getGPUFeatureStatus() API', () => {
it('returns the graphic features statuses', () => {
const features = app.getGPUFeatureStatus()
expect(features).to.have.own.property('webgl').that.is.a('string')
expect(features).to.have.own.property('gpu_compositing').that.is.a('string')
expect(features).to.have.ownProperty('webgl').that.is.a('string')
expect(features).to.have.ownProperty('gpu_compositing').that.is.a('string')
})
})
describe('getGPUInfo() API', () => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'gpu-info.js')
const appPath = path.join(fixturesPath, 'api', 'gpu-info.js')
const getGPUInfo = async (type) => {
const appProcess = ChildProcess.spawn(remote.process.execPath, [appPath, type])
const getGPUInfo = async (type: string) => {
const appProcess = cp.spawn(process.execPath, [appPath, type])
let gpuInfoData = ''
let errorData = ''
appProcess.stdout.on('data', (data) => {
@ -1013,11 +994,11 @@ describe('app module', () => {
return Promise.reject(new Error(errorData))
}
}
const verifyBasicGPUInfo = async (gpuInfo) => {
const verifyBasicGPUInfo = async (gpuInfo: any) => {
// Devices information is always present in the available info.
expect(gpuInfo).to.have.own.property('gpuDevice')
expect(gpuInfo).to.have.ownProperty('gpuDevice')
.that.is.an('array')
.and.is.not.empty()
.and.does.not.equal([])
const device = gpuInfo.gpuDevice[0]
expect(device).to.be.an('object')
@ -1040,11 +1021,11 @@ describe('app module', () => {
expect(completeInfo).to.deep.equal(basicInfo)
} else {
// Gl version is present in the complete info.
expect(completeInfo).to.have.own.property('auxAttributes')
expect(completeInfo).to.have.ownProperty('auxAttributes')
.that.is.an('object')
expect(completeInfo.auxAttributes).to.have.own.property('glVersion')
expect(completeInfo.auxAttributes).to.have.ownProperty('glVersion')
.that.is.a('string')
.and.not.empty()
.and.does.not.equal([])
}
})
@ -1056,8 +1037,8 @@ describe('app module', () => {
})
describe('sandbox options', () => {
let appProcess = null
let server = null
let appProcess: cp.ChildProcess = null as any
let server: net.Server = null as any
const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-mixed-sandbox' : '/tmp/electron-mixed-sandbox'
beforeEach(function (done) {
@ -1097,22 +1078,22 @@ describe('app module', () => {
describe('when app.enableSandbox() is called', () => {
it('adds --enable-sandbox to all renderer processes', done => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'mixed-sandbox-app')
appProcess = ChildProcess.spawn(remote.process.execPath, [appPath, '--app-enable-sandbox'])
const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app')
appProcess = cp.spawn(process.execPath, [appPath, '--app-enable-sandbox'])
server.once('error', error => { done(error) })
server.on('connection', client => {
client.once('data', data => {
const argv = JSON.parse(data)
client.once('data', (data) => {
const argv = JSON.parse(data.toString())
expect(argv.sandbox).to.include('--enable-sandbox')
expect(argv.sandbox).to.not.include('--no-sandbox')
expect(argv.noSandbox).to.include('--enable-sandbox')
expect(argv.noSandbox).to.not.include('--no-sandbox')
expect(argv.noSandboxDevtools).to.be.true()
expect(argv.sandboxDevtools).to.be.true()
expect(argv.noSandboxDevtools).to.equal(true)
expect(argv.sandboxDevtools).to.equal(true)
done()
})
@ -1122,22 +1103,22 @@ describe('app module', () => {
describe('when the app is launched with --enable-sandbox', () => {
it('adds --enable-sandbox to all renderer processes', done => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'mixed-sandbox-app')
appProcess = ChildProcess.spawn(remote.process.execPath, [appPath, '--enable-sandbox'])
const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app')
appProcess = cp.spawn(process.execPath, [appPath, '--enable-sandbox'])
server.once('error', error => { done(error) })
server.on('connection', client => {
client.once('data', data => {
const argv = JSON.parse(data)
const argv = JSON.parse(data.toString())
expect(argv.sandbox).to.include('--enable-sandbox')
expect(argv.sandbox).to.not.include('--no-sandbox')
expect(argv.noSandbox).to.include('--enable-sandbox')
expect(argv.noSandbox).to.not.include('--no-sandbox')
expect(argv.noSandboxDevtools).to.be.true()
expect(argv.sandboxDevtools).to.be.true()
expect(argv.noSandboxDevtools).to.equal(true)
expect(argv.sandboxDevtools).to.equal(true)
done()
})
@ -1156,6 +1137,10 @@ describe('app module', () => {
const dockDescribe = process.platform === 'darwin' ? describe : describe.skip
dockDescribe('dock APIs', () => {
after(async () => {
await app.dock.show()
})
describe('dock.setMenu', () => {
it('can be retrieved via dock.getMenu', () => {
expect(app.dock.getMenu()).to.equal(null)
@ -1173,7 +1158,7 @@ describe('app module', () => {
describe('dock.bounce', () => {
it('should return -1 for unknown bounce type', () => {
expect(app.dock.bounce('bad type')).to.equal(-1)
expect(app.dock.bounce('bad type' as any)).to.equal(-1)
})
it('should return a positive number for informational type', () => {
@ -1223,8 +1208,8 @@ describe('app module', () => {
expect(app.dock.show()).to.be.a('promise')
})
it('eventually fulfills', () => {
expect(app.dock.show()).to.be.eventually.fulfilled()
it('eventually fulfills', async () => {
await expect(app.dock.show()).to.eventually.be.fulfilled.equal(undefined)
})
})
@ -1241,32 +1226,32 @@ describe('app module', () => {
expect(app.whenReady()).to.be.a('promise')
})
it('becomes fulfilled if the app is already ready', () => {
expect(app.isReady()).to.be.true()
expect(app.whenReady()).to.be.eventually.fulfilled()
it('becomes fulfilled if the app is already ready', async () => {
expect(app.isReady()).to.equal(true)
await expect(app.whenReady()).to.be.eventually.fulfilled.equal(undefined)
})
})
describe('commandLine.hasSwitch', () => {
it('returns true when present', () => {
app.commandLine.appendSwitch('foobar1')
expect(app.commandLine.hasSwitch('foobar1')).to.be.true()
expect(app.commandLine.hasSwitch('foobar1')).to.equal(true)
})
it('returns false when not present', () => {
expect(app.commandLine.hasSwitch('foobar2')).to.be.false()
expect(app.commandLine.hasSwitch('foobar2')).to.equal(false)
})
})
describe('commandLine.hasSwitch (existing argv)', () => {
it('returns true when present', async () => {
const { hasSwitch } = await runTestApp('command-line', '--foobar')
expect(hasSwitch).to.be.true()
expect(hasSwitch).to.equal(true)
})
it('returns false when not present', async () => {
const { hasSwitch } = await runTestApp('command-line')
expect(hasSwitch).to.be.false()
expect(hasSwitch).to.equal(false)
})
})
@ -1335,9 +1320,9 @@ describe('default behavior', () => {
})
})
async function runTestApp (name, ...args) {
const appPath = path.join(__dirname, 'fixtures', 'api', name)
const electronPath = remote.getGlobal('process').execPath
async function runTestApp (name: string, ...args: any[]) {
const appPath = path.join(fixturesPath, 'api', name)
const electronPath = process.execPath
const appProcess = cp.spawn(electronPath, [appPath, ...args])
let output = ''

View file

@ -0,0 +1,40 @@
import { EventEmitter } from "electron";
/**
* @fileoverview A set of helper functions to make it easier to work
* with events in async/await manner.
*/
/**
* @param {!EventTarget} target
* @param {string} eventName
* @return {!Promise<!Event>}
*/
export const waitForEvent = (target: EventTarget, eventName: string) => {
return new Promise(resolve => {
target.addEventListener(eventName, resolve, { once: true })
})
}
/**
* @param {!EventEmitter} emitter
* @param {string} eventName
* @return {!Promise<!Array>} With Event as the first item.
*/
export const emittedOnce = (emitter: EventEmitter, eventName: string) => {
return emittedNTimes(emitter, eventName, 1).then(([result]) => result)
}
export const emittedNTimes = (emitter: EventEmitter, eventName: string, times: number) => {
const events: any[][] = []
return new Promise<any[][]>(resolve => {
const handler = (...args: any[]) => {
events.push(args)
if (events.length === times) {
emitter.removeListener(eventName, handler)
resolve(events)
}
}
emitter.on(eventName, handler)
})
}

90
spec-main/index.js Normal file
View file

@ -0,0 +1,90 @@
const Module = require('module')
const path = require('path')
const v8 = require('v8')
Module.globalPaths.push(path.resolve(__dirname, '../spec/node_modules'))
// We want to terminate on errors, not throw up a dialog
process.on('uncaughtException', (err) => {
console.error('Unhandled exception in main spec runner:', err)
process.exit(1)
})
// Tell ts-node which tsconfig to use
process.env.TS_NODE_PROJECT = path.resolve(__dirname, '../tsconfig.spec.json')
const { app } = require('electron')
v8.setFlagsFromString('--expose_gc')
app.commandLine.appendSwitch('js-flags', '--expose_gc')
// Prevent the spec runner quiting when the first window closes
app.on('window-all-closed', () => null)
// TODO: This API should _probably_ only be enabled for the specific test that needs it
// not the entire test suite
app.commandLine.appendSwitch('ignore-certificate-errors')
app.whenReady().then(() => {
require('ts-node/register')
const argv = require('yargs')
.boolean('ci')
.string('g').alias('g', 'grep')
.boolean('i').alias('i', 'invert')
.argv
const isCi = !!argv.ci
global.isCI = isCi
const Mocha = require('mocha')
const mochaOptions = {}
if (process.env.MOCHA_REPORTER) {
mochaOptions.reporter = process.env.MOCHA_REPORTER
}
if (process.env.MOCHA_MULTI_REPORTERS) {
mochaOptions.reporterOptions = {
reporterEnabled: process.env.MOCHA_MULTI_REPORTERS
}
}
const mocha = new Mocha(mochaOptions)
if (!process.env.MOCHA_REPORTER) {
mocha.ui('bdd').reporter('tap')
}
mocha.timeout(isCi ? 30000 : 10000)
if (argv.grep) mocha.grep(argv.grep)
if (argv.invert) mocha.invert()
// Read all test files.
const walker = require('walkdir').walk(__dirname, {
no_recurse: true
})
// This allows you to run specific modules only:
// npm run test -match=menu
const moduleMatch = process.env.npm_config_match
? new RegExp(process.env.npm_config_match, 'g')
: null
walker.on('file', (file) => {
if (/-spec\.[tj]s$/.test(file) &&
(!moduleMatch || moduleMatch.test(file))) {
mocha.addFile(file)
}
})
walker.on('end', () => {
const runner = mocha.run(() => {
if (isCi && runner.hasOnly) {
try {
throw new Error('A spec contains a call to it.only or describe.only and should be reverted.')
} catch (error) {
console.error(error.stack || error)
}
process.exit(1)
}
process.exit(runner.failures)
})
})
})

6
spec-main/package.json Normal file
View file

@ -0,0 +1,6 @@
{
"name": "electron-test-main",
"productName": "Electron Test Main",
"main": "index.js",
"version": "0.1.0"
}

View file

@ -0,0 +1,26 @@
import { expect } from 'chai'
import { BrowserWindow, WebContents } from 'electron'
import { emittedOnce } from './events-helpers';
export const closeWindow = async (
window: BrowserWindow | null = null,
{ assertNotWindows } = { assertNotWindows: true }
) => {
if (window && !window.isDestroyed()) {
const isClosed = emittedOnce(window, 'closed')
window.setClosable(true)
window.close()
await isClosed
}
if (assertNotWindows) {
expect(BrowserWindow.getAllWindows()).to.have.lengthOf(0)
}
}
exports.waitForWebContentsToLoad = async (webContents: WebContents) => {
const didFinishLoadPromise = emittedOnce(webContents, 'did-finish-load')
if (webContents.isLoadingMainFrame()) {
await didFinishLoadPromise
}
}

44
spec/package-lock.json generated
View file

@ -5,9 +5,8 @@
"requires": true,
"dependencies": {
"abstract-socket": {
"version": "github:nornagon/node-abstractsocket#7d9c770f9ffef14373349034f8820ff059879845",
"from": "github:nornagon/node-abstractsocket#v8-compat",
"dev": true,
"version": "2.0.0",
"resolved": "github:nornagon/node-abstractsocket#7d9c770f9ffef14373349034f8820ff059879845",
"optional": true,
"requires": {
"bindings": "^1.2.1",
@ -66,7 +65,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.4.0.tgz",
"integrity": "sha512-7znEVX22Djn+nYjxCWKDne0RRloa9XfYa84yk3s+HkE3LpDYZmhArYr9O9huBoHY3/oXispx5LorIX7Sl2CgSQ==",
"dev": true,
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
@ -243,14 +241,12 @@
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"optional": true
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"optional": true
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cross-spawn": {
"version": "6.0.5",
@ -285,6 +281,19 @@
"put": "0.0.6",
"safe-buffer": "^5.1.1",
"xml2js": "^0.4.17"
},
"dependencies": {
"abstract-socket": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abstract-socket/-/abstract-socket-2.0.0.tgz",
"integrity": "sha1-2DyT598w0n4j8+gqdj5/XnjZFvk=",
"dev": true,
"optional": true,
"requires": {
"bindings": "^1.2.1",
"nan": "^2.0.9"
}
}
}
},
"debug": {
@ -459,7 +468,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true,
"optional": true
},
"find-up": {
@ -672,8 +680,7 @@
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"optional": true
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
@ -778,9 +785,8 @@
},
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"optional": true
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mkdirp": {
"version": "0.5.1",
@ -1100,8 +1106,7 @@
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"optional": true
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"pump": {
"version": "2.0.1",
@ -1151,9 +1156,8 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@ -1363,7 +1367,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@ -1490,8 +1493,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"optional": true
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"walkdir": {
"version": "0.3.2",

View file

@ -7,7 +7,6 @@
"postinstall": "node ../tools/run-if-exists.js node_modules/robotjs node-gyp rebuild"
},
"devDependencies": {
"abstract-socket": "github:nornagon/node-abstractsocket#v8-compat",
"basic-auth": "^2.0.1",
"bluebird": "^3.5.3",
"chai": "^4.2.0",
@ -33,6 +32,7 @@
"yargs": "^12.0.5"
},
"optionalDependencies": {
"abstract-socket": "github:nornagon/node-abstractsocket#v8-compat",
"robotjs": "github:nornagon/robotjs#node-12"
}
}

View file

@ -17,6 +17,12 @@
const electron = require('electron')
const { remote, ipcRenderer } = electron
// Set up chai-as-promised here first to avoid conflicts
// It must be loaded first or really strange things happen inside
// chai that cause test failures
// DO NOT MOVE, REMOVE OR EDIT THIS LINE
require('chai').use(require('chai-as-promised'))
// Check if we are running in CI.
const isCi = remote.getGlobal('isCi')

10
tsconfig.spec.json Normal file
View file

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "spec-main"
},
"include": [
"spec-main",
"typings"
]
}

View file

@ -13,6 +13,7 @@ declare namespace NodeJS {
interface V8UtilBinding {
getHiddenValue<T>(obj: any, key: string): T;
setHiddenValue<T>(obj: any, key: string, value: T): void;
requestGarbageCollectionForTesting(): void;
}
interface Process {
/**