diff --git a/README.md b/README.md index fcb9eaf6..6000bdc1 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ And then add the plugin's name to the list of build plugins in `netlify.toml` fi *note:* this plugin assumes you have already installed Cypress as a dev NPM dependency. +### Chromium install + +This plugin installs [via Puppeteer](https://github.com/puppeteer/puppeteer) Chromium browser, which is also cached inside `./node_modules` folder. + ## How does it work When Netlify Build runs, it "knows" the output folder name and calls the `netlify-plugin-cypress` after the build has finished with that folder. Then the plugin runs Cypress tests using its [NPM module API](https://on.cypress.io/module-api). If the tests pass, the plugin finishes and the Netlify deploy starts. @@ -173,6 +177,27 @@ package = "netlify-plugin-cypress" See [cypress-example-kitchensink](https://github.com/cypress-io/cypress-example-kitchensink) for instance. +### Chromium + +By default all tests run using built-in Electron browser. If you want to use Chromium: + +```toml +[build] +command = "npm run build" +publish = "build" + [build.environment] + # cache Cypress binary in local "node_modules" folder + # so Netlify caches it + CYPRESS_CACHE_FOLDER = "./node_modules/CypressBinary" + # set TERM variable for terminal output + TERM = "xterm" + +[[plugins]] +package = "netlify-plugin-cypress" + [plugins.inputs] + browser = "chromium" +``` + ### testing SPA routes SPAs need catch-all redirect setup to make non-root paths accesssible by tests. You can enable this with `spa` parameter. diff --git a/circle.yml b/circle.yml index 4a2c8c94..763d0aa6 100644 --- a/circle.yml +++ b/circle.yml @@ -89,6 +89,19 @@ jobs: environment: DEBUG: netlify-plugin-cypress + 'test-using-chromium': + executor: cypress/base-12-14-0 + steps: + # all dependencies were installed in previous job + - attach_workspace: + at: ~/ + - run: + name: Netlify Build 🏗 + command: npx netlify build + working_directory: tests/use-chromium + environment: + DEBUG: netlify-plugin-cypress + routing: executor: cypress/base-12-14-0 steps: @@ -123,6 +136,9 @@ workflows: - 'test-prebuild-only': requires: - cypress/install + - test-using-chromium: + requires: + - cypress/install - routing: requires: - cypress/install @@ -134,6 +150,7 @@ workflows: - 'recording test' - 'test-twice' - 'test-prebuild-only' + - test-using-chromium - 'routing' filters: branches: diff --git a/manifest.yml b/manifest.yml index 5fa7d872..f462bf50 100644 --- a/manifest.yml +++ b/manifest.yml @@ -11,6 +11,11 @@ inputs: # by default run the tests - name: skip default: false + # by default the tests run in Electron + # but because of the dependency we download Chromium + # so you can set "browser = electron" + - name: browser + default: electron # tells the plugin how to start the server using custom command # and waiting for an url, record to the dashboard, tag, etc diff --git a/netlify.toml b/netlify.toml index 79f878b3..6ae29701 100644 --- a/netlify.toml +++ b/netlify.toml @@ -10,8 +10,9 @@ publish = "public" [[plugins]] # local Cypress plugin will test our site after it is built package = "." - # [plugins.inputs] - # spec = 'cypress/integration/spec.js' + [plugins.inputs] + # browser = "electron" + # spec = 'cypress/integration/spec.js' # [plugins.inputs.preBuild] # start = 'npm start' # wait-on = 'http://localhost:5000' diff --git a/package-lock.json b/package-lock.json index 070e088e..35a8f0b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4111,12 +4111,6 @@ } } }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true - }, "node-releases": { "version": "1.1.70", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz", @@ -6267,6 +6261,15 @@ "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, + "@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, "@typescript-eslint/eslint-plugin": { "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", @@ -7786,8 +7789,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -7853,8 +7855,7 @@ "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "basic-auth": { "version": "2.0.1", @@ -7910,7 +7911,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.4.tgz", "integrity": "sha512-7tdr4EpSd7jJ6tuQ21vu2ke8w7pNEstzj1O8wwq6sNNzO3UDi5MA8Gny/gquCj7r2C6fHudg8tKRGyjRgmvNxQ==", - "dev": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -7921,7 +7921,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -8081,7 +8080,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8256,7 +8254,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -8281,8 +8278,7 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, "buffer-es6": { "version": "4.9.3", @@ -8664,8 +8660,7 @@ "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "chrome-trace-event": { "version": "1.0.2", @@ -9406,8 +9401,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -11434,6 +11428,11 @@ "typescript": "^3.8.3" } }, + "devtools-protocol": { + "version": "0.0.847576", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.847576.tgz", + "integrity": "sha512-0M8kobnSQE0Jmly7Mhbeq0W/PpZfnuK+WjN2ZRVPbGqYwCHCioAVp84H0TcLimgECcN5H976y5QiXMGBC9JKmg==" + }, "diff-sequences": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", @@ -13914,8 +13913,7 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-extra": { "version": "8.1.0", @@ -13952,8 +13950,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "2.1.2", @@ -14133,7 +14130,6 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -15020,8 +15016,7 @@ "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "iferr": { "version": "0.1.5", @@ -15197,7 +15192,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -19365,7 +19359,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -19533,6 +19526,11 @@ "minimist": "^1.2.5" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -19832,12 +19830,6 @@ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", "dev": true }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true - }, "p-map": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", @@ -20437,10 +20429,9 @@ } }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", - "dev": true + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-forge": { "version": "0.9.0", @@ -25207,8 +25198,7 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" }, "performance-now": { "version": "2.1.0", @@ -25266,7 +25256,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, "requires": { "find-up": "^4.0.0" }, @@ -25275,7 +25264,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -25285,7 +25273,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "requires": { "p-locate": "^4.1.0" } @@ -25294,7 +25281,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "requires": { "p-try": "^2.0.0" } @@ -25303,7 +25289,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "requires": { "p-limit": "^2.2.0" } @@ -25311,14 +25296,12 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" } } }, @@ -26778,8 +26761,7 @@ "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, "promise": { "version": "8.1.0", @@ -26842,6 +26824,11 @@ "ipaddr.js": "1.9.1" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -26929,6 +26916,51 @@ "escape-goat": "^2.0.0" } }, + "puppeteer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-7.0.1.tgz", + "integrity": "sha512-04V05BKQdloUCOa7JyQBaNXPIiVByz1eAFAElcrpMHIQkfu22J0RKFhRWkXZGXdl03yoHuaZwqyB/qG7YJu5Ew==", + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.847576", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ws": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", + "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==" + } + } + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -30613,11 +30645,21 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, "tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, "requires": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -30630,7 +30672,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -31334,7 +31375,6 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dev": true, "requires": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -33916,7 +33956,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -33926,7 +33965,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, "requires": { "pend": "~1.2.0" } diff --git a/package.json b/package.json index d19fc31e..a9eb0e84 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "dependencies": { "debug": "4.1.1", "got": "10.7.0", - "local-web-server": "^4.2.1" + "local-web-server": "^4.2.1", + "puppeteer": "^7.0.1" }, "repository": { "type": "git", diff --git a/src/index.js b/src/index.js index 3afeb082..f91b3e98 100644 --- a/src/index.js +++ b/src/index.js @@ -2,9 +2,11 @@ const LocalWebServer = require('local-web-server') const debug = require('debug')('netlify-plugin-cypress') const debugVerbose = require('debug')('netlify-plugin-cypress:verbose') -const { ping } = require('./utils') +const { ping, getBrowserPath } = require('./utils') const fs = require('fs') +const DEFAULT_BROWSER = 'electron' + function serveFolder(directory, port, spa) { if (typeof spa === 'boolean') { if (spa) { @@ -88,7 +90,13 @@ async function waitOnMaybe(buildUtils, options = {}) { } } -async function runCypressTests(baseUrl, record, spec, group, tag) { +const isValidBrowser = (name) => name === 'electron' || name === 'chromium' + +async function runCypressTests(baseUrl, record, spec, group, tag, browser) { + if (!isValidBrowser(browser)) { + throw new Error(`Invalid browser name "${browser}"`) + } + // we will use Cypress via its NPM module API // https://on.cypress.io/module-api const cypress = require('cypress') @@ -100,6 +108,9 @@ async function runCypressTests(baseUrl, record, spec, group, tag) { ciBuildId = process.env.BUILD_ID } + const browserPath = + browser === 'electron' ? 'electron' : await getBrowserPath() + debug('run cypress params %o', { baseUrl, record, @@ -107,6 +118,7 @@ async function runCypressTests(baseUrl, record, spec, group, tag) { group, tag, ciBuildId, + browser: browserPath, }) return await cypress.run({ @@ -118,6 +130,8 @@ async function runCypressTests(baseUrl, record, spec, group, tag) { group, tag, ciBuildId, + browser: browserPath, + headless: true, }) } @@ -208,6 +222,7 @@ async function postBuild({ group, tag, spa, + browser, errorCallback, }) { const port = 8080 @@ -224,7 +239,14 @@ async function postBuild({ const baseUrl = `http://localhost:${port}` - const results = await runCypressTests(baseUrl, record, spec, group, tag) + const results = await runCypressTests( + baseUrl, + record, + spec, + group, + tag, + browser, + ) await new Promise((resolve, reject) => { server.close((err) => { @@ -254,6 +276,8 @@ module.exports = { return } + const browser = arg.inputs.browser || DEFAULT_BROWSER + const closeServer = startServerMaybe(arg.utils.run, preBuildInputs) await waitOnMaybe(arg.utils.build, preBuildInputs) @@ -272,7 +296,14 @@ module.exports = { } } - const results = await runCypressTests(baseUrl, record, spec, group, tag) + const results = await runCypressTests( + baseUrl, + record, + spec, + group, + tag, + browser, + ) if (closeServer) { debug('closing server') @@ -295,6 +326,8 @@ module.exports = { const fullPublishFolder = arg.constants.PUBLISH_DIR debug('folder to publish is "%s"', fullPublishFolder) + const browser = arg.inputs.browser || DEFAULT_BROWSER + // only if the user wants to record the tests and has set the record key // then we should attempt recording const record = hasRecordKey() && Boolean(arg.inputs.record) @@ -322,6 +355,7 @@ module.exports = { group, tag, spa, + browser, errorCallback, }) }, @@ -362,6 +396,8 @@ module.exports = { return errorCallback('Missing DEPLOY_PRIME_URL') } + const browser = arg.inputs.browser || DEFAULT_BROWSER + // only if the user wants to record the tests and has set the record key // then we should attempt recording const hasKey = hasRecordKey() @@ -394,6 +430,7 @@ module.exports = { spec, group, tag, + browser, ) processCypressResults(results, errorCallback) }, diff --git a/src/utils.js b/src/utils.js index edbff7d5..6bf80357 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,5 @@ // @ts-check +const puppeteer = require('puppeteer') const got = require('got') const debug = require('debug')('netlify-plugin-cypress') const debugVerbose = require('debug')('netlify-plugin-cypress:verbose') @@ -14,24 +15,45 @@ const ping = (url, timeout) => { return got(url, { retry: { limit: 30, - calculateDelay({attemptCount, retryOptions, error}) { + calculateDelay({ attemptCount, retryOptions, error }) { const now = +new Date() const elapsed = now - start debugVerbose(`attempt ${attemptCount} ${elapsed}ms ${error.message}`) if (elapsed > timeout) { - debug('%s timed out after %dms, timeout was %dms', - url, elapsed, timeout) - console.error('%s timed out after %dms, timeout was %dms', - url, elapsed, timeout) + debug( + '%s timed out after %dms, timeout was %dms', + url, + elapsed, + timeout, + ) + console.error( + '%s timed out after %dms, timeout was %dms', + url, + elapsed, + timeout, + ) return 0 } return 1000 - } - } + }, + }, }) } +const getBrowserPath = async () => { + const browserFetcher = puppeteer.createBrowserFetcher() + const revisions = await browserFetcher.localRevisions() + debug('local Chromium revisions %o', revisions) + if (revisions.length <= 0) { + throw new Error('Could not find local browser') + } + const info = await browserFetcher.revisionInfo(revisions[0]) + debug('found Chromium %o', info) + return info.executablePath +} + module.exports = { - ping + ping, + getBrowserPath, } diff --git a/tests/use-chromium/cypress.json b/tests/use-chromium/cypress.json new file mode 100644 index 00000000..e36f9847 --- /dev/null +++ b/tests/use-chromium/cypress.json @@ -0,0 +1,5 @@ +{ + "pluginsFile": false, + "supportFile": false, + "fixturesFolder": false +} diff --git a/tests/use-chromium/cypress/integration/spec.js b/tests/use-chromium/cypress/integration/spec.js new file mode 100644 index 00000000..27608f29 --- /dev/null +++ b/tests/use-chromium/cypress/integration/spec.js @@ -0,0 +1,6 @@ +/// +describe('basic', () => { + it('runs unit test', () => { + expect(2 + 3).to.equal(5) + }) +}) diff --git a/tests/use-chromium/netlify.toml b/tests/use-chromium/netlify.toml new file mode 100644 index 00000000..30b29026 --- /dev/null +++ b/tests/use-chromium/netlify.toml @@ -0,0 +1,10 @@ +[build] +command = "echo 'Netlify build command ...'" +publish = "public" + +[[plugins]] + # local Cypress plugin will test our site after it is built + # in production, please use: package = "netlify-plugin-cypress" + package = "../../" + [plugins.inputs] + browser = "chromium" diff --git a/tests/use-chromium/public/index.html b/tests/use-chromium/public/index.html new file mode 100644 index 00000000..91462584 --- /dev/null +++ b/tests/use-chromium/public/index.html @@ -0,0 +1 @@ +

Basic