diff --git a/.circleci/config.yml b/.circleci/config.yml index 2c670c0e0e..314597f729 100755 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,9 +1,13 @@ version: 2 + +defaults: &defaults + working_directory: ~/project/nuxt + docker: + - image: banian/node-headless-chrome + jobs: - build: - working_directory: /usr/src/app - docker: - - image: banian/node-headless-chrome + setup: + <<: *defaults steps: # Checkout repository - checkout @@ -23,17 +27,95 @@ jobs: paths: - "node_modules" - # Test - - run: - name: Tests - command: NODE_ENV=test yarn test && yarn coverage + # Persist files + - persist_to_workspace: + root: ~/project + paths: + - nuxt - # Release edge + lint: + <<: *defaults + steps: + - attach_workspace: + at: ~/project - run: - name: Publish nuxt-edge + name: ESLint + command: yarn lint + + build: + <<: *defaults + steps: + - attach_workspace: + at: ~/project + - run: + name: Build Fixtures + command: yarn build-fixtures + - persist_to_workspace: + root: ~/project + paths: + - nuxt/test/fixtures + + test: + <<: *defaults + steps: + - attach_workspace: + at: ~/project + - run: + name: Test + command: yarn test:unit && yarn coverage + environment: + - NODE_ENV: "test" + + test-e2e: + <<: *defaults + steps: + - attach_workspace: + at: ~/project + - run: + name: Test (e2e) + command: yarn test:e2e && yarn coverage + environment: + - NODE_ENV: "test" + + release: + <<: *defaults + steps: + - attach_workspace: + at: ~/project + - run: + name: release command: | if [ "${CIRCLE_BRANCH}" == "dev" ]; then echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc echo "//registry.yarnpkg.com/:_authToken=$NPM_TOKEN" >> ~/.npmrc ./scripts/release-edge fi + +workflows: + version: 2 + setup-and-parallel-test: + jobs: + - setup + + - lint: + requires: + - setup + + - build: + requires: + - setup + + - test: + requires: + - build + + - test-e2e: + requires: + - build + + - release: + requires: + - build + - lint + - test + - test-e2e diff --git a/.eslintrc.js b/.eslintrc.js index 861dfbbdd1..e1b3df62e8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,8 @@ module.exports = { }, env: { browser: true, - node: true + node: true, + 'jest/globals': true }, extends: [ 'standard', @@ -14,9 +15,9 @@ module.exports = { 'plugin:import/errors', 'plugin:import/warnings' ], - // required to lint *.vue files plugins: [ - 'html' + 'html', + 'jest' ], settings: { 'import/resolver': { diff --git a/appveyor.yml b/appveyor.yml index ae646e0092..056894b2e6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,10 +19,13 @@ install: test_script: # Output useful info for debugging. - node --version - - npm --version + # - npm --version - yarn --version # run tests - yarn test # Don't actually build. build: off + +# Do not build feature branch with open Pull Requests +skip_branch_with_pr: true diff --git a/examples/async-component-injection/package.json b/examples/async-component-injection/package.json index 4aeda9d845..c2a55b2829 100644 --- a/examples/async-component-injection/package.json +++ b/examples/async-component-injection/package.json @@ -1,5 +1,5 @@ { - "name": "components-injection-nuxt", + "name": "example-async-components-injection", "dependencies": { "nuxt": "latest" }, diff --git a/examples/async-data/package.json b/examples/async-data/package.json index 028496f7fe..bdab722095 100644 --- a/examples/async-data/package.json +++ b/examples/async-data/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-async-data", + "name": "example-async-data", "dependencies": { "axios": "latest", "nuxt": "latest" diff --git a/examples/auth-routes/package.json b/examples/auth-routes/package.json index dd7c4c3926..9e1ed5c80f 100644 --- a/examples/auth-routes/package.json +++ b/examples/auth-routes/package.json @@ -1,5 +1,5 @@ { - "name": "auth-routes", + "name": "example-auth-routes", "dependencies": { "axios": "^0.16.1", "body-parser": "^1.17.2", diff --git a/examples/axios/package.json b/examples/axios/package.json index 377e6287c9..aaa5c56dcf 100644 --- a/examples/axios/package.json +++ b/examples/axios/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-proxy", + "name": "example-axios", "version": "1.0.0", "dependencies": { "@nuxtjs/axios": "^5.0.0", diff --git a/examples/cached-components/package.json b/examples/cached-components/package.json index 1e7850343b..597fe8ab6d 100644 --- a/examples/cached-components/package.json +++ b/examples/cached-components/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-cached-components", + "name": "example-cached-components", "dependencies": { "lru-cache": "^4.0.2", "nuxt": "latest" diff --git a/examples/coffeescript/package.json b/examples/coffeescript/package.json index 759d04ff0f..f1e6c2e195 100644 --- a/examples/coffeescript/package.json +++ b/examples/coffeescript/package.json @@ -1,5 +1,5 @@ { - "name": "coffeescript", + "name": "example-coffeescript", "version": "1.0.0", "description": "Nuxt.js with CoffeeScript", "author": "Alex Ananiev ", diff --git a/examples/custom-build/package.json b/examples/custom-build/package.json index bca372acaa..262147d6fe 100644 --- a/examples/custom-build/package.json +++ b/examples/custom-build/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-custom-build", + "name": "example-custom-build", "description": "", "dependencies": { "nuxt": "latest" diff --git a/examples/custom-layouts/package.json b/examples/custom-layouts/package.json index 4b5f4b7874..a5b7a731d9 100644 --- a/examples/custom-layouts/package.json +++ b/examples/custom-layouts/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-custom-layouts", + "name": "example-custom-layouts", "dependencies": { "nuxt": "latest" }, diff --git a/examples/custom-loading/package.json b/examples/custom-loading/package.json index c177c2338b..b2dcfbc2ee 100644 --- a/examples/custom-loading/package.json +++ b/examples/custom-loading/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-custom-loading", + "name": "example-custom-loading", "dependencies": { "nuxt": "latest" }, diff --git a/examples/custom-routes/package.json b/examples/custom-routes/package.json index 437be36725..15c615ff87 100644 --- a/examples/custom-routes/package.json +++ b/examples/custom-routes/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-custom-routes", + "name": "example-custom-routes", "dependencies": { "axios": "latest", "nuxt": "latest" diff --git a/examples/custom-server/package.json b/examples/custom-server/package.json index d686d66254..5afd1369ec 100644 --- a/examples/custom-server/package.json +++ b/examples/custom-server/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-custom-server", + "name": "example-custom-server", "dependencies": { "express": "^4.15.3", "nuxt": "latest" diff --git a/examples/dynamic-components/package.json b/examples/dynamic-components/package.json index 7486edc9cd..31f52dbf45 100644 --- a/examples/dynamic-components/package.json +++ b/examples/dynamic-components/package.json @@ -1,5 +1,5 @@ { - "name": "dynamic-components-nuxt", + "name": "example-dynamic-components", "dependencies": { "chart.js": "^2.7.0", "nuxt": "latest", diff --git a/examples/dynamic-layouts/package.json b/examples/dynamic-layouts/package.json index cd97f88ca2..4ec8d06bac 100644 --- a/examples/dynamic-layouts/package.json +++ b/examples/dynamic-layouts/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-dynamic-layouts", + "name": "example-dynamic-layouts", "dependencies": { "nuxt": "latest" }, diff --git a/examples/global-css/package.json b/examples/global-css/package.json index 1525d69e4e..61f426698d 100644 --- a/examples/global-css/package.json +++ b/examples/global-css/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-global-css", + "name": "example-global-css", "dependencies": { "bulma": "^0.5.1", "nuxt": "latest" diff --git a/examples/hello-world/package.json b/examples/hello-world/package.json index 2e16d42040..0cc6a5c7c8 100644 --- a/examples/hello-world/package.json +++ b/examples/hello-world/package.json @@ -1,5 +1,5 @@ { - "name": "hello-nuxt", + "name": "example-hello-world", "dependencies": { "nuxt": "latest" }, diff --git a/examples/i18n/package.json b/examples/i18n/package.json index 0761757ce8..fbc1b45df5 100644 --- a/examples/i18n/package.json +++ b/examples/i18n/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-i18n", + "name": "example-i18n", "dependencies": { "nuxt": "latest", "vue-i18n": "^7.3.2" diff --git a/examples/jsx/package.json b/examples/jsx/package.json index d6478c6544..9922994937 100644 --- a/examples/jsx/package.json +++ b/examples/jsx/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-jsx", + "name": "example-jsx", "dependencies": { "nuxt": "latest" }, diff --git a/examples/layout-transitions/package.json b/examples/layout-transitions/package.json index 822831ec96..1cc2bc34fe 100644 --- a/examples/layout-transitions/package.json +++ b/examples/layout-transitions/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-layout-transitions", + "name": "example-layout-transitions", "dependencies": { "axios": "^0.15.3", "nuxt": "latest" diff --git a/examples/markdownit/package.json b/examples/markdownit/package.json index bdbe75cd3b..391d1fd42c 100644 --- a/examples/markdownit/package.json +++ b/examples/markdownit/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-markdownit", + "name": "example-markdownit", "version": "1.0.0", "dependencies": { "@nuxtjs/markdownit": "^1.1.2", diff --git a/examples/meta-info/package.json b/examples/meta-info/package.json index b06c061ade..2e5f33b3b4 100644 --- a/examples/meta-info/package.json +++ b/examples/meta-info/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-head-elements", + "name": "example-meta-info", "dependencies": { "nuxt": "latest" }, diff --git a/examples/middleware/package.json b/examples/middleware/package.json index 7d068bad95..7c45ac8e61 100644 --- a/examples/middleware/package.json +++ b/examples/middleware/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-middleware", + "name": "example-middleware", "dependencies": { "nuxt": "latest" }, diff --git a/examples/nested-components/package.json b/examples/nested-components/package.json index cf348d5c6f..49f4d99588 100644 --- a/examples/nested-components/package.json +++ b/examples/nested-components/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-nested-components", + "name": "example-nested-components", "dependencies": { "nuxt": "latest" }, diff --git a/examples/nested-routes/package.json b/examples/nested-routes/package.json index d3d40f04d3..350733131c 100644 --- a/examples/nested-routes/package.json +++ b/examples/nested-routes/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-nested-routes", + "name": "example-nested-routes", "dependencies": { "nuxt": "latest" }, diff --git a/examples/no-ssr/package.json b/examples/no-ssr/package.json index 9e2167e845..1e9e185ae4 100644 --- a/examples/no-ssr/package.json +++ b/examples/no-ssr/package.json @@ -1,5 +1,5 @@ { - "name": "no-ssr-cmp-nuxt", + "name": "example-no-ssr", "dependencies": { "nuxt": "latest" }, diff --git a/examples/plugins-vendor/package.json b/examples/plugins-vendor/package.json index 995af2c330..05456a14c7 100644 --- a/examples/plugins-vendor/package.json +++ b/examples/plugins-vendor/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-plugins-vendor", + "name": "example-plugins-vendor", "dependencies": { "axios": "^0.16.2", "mini-toastr": "^0.6.5", diff --git a/examples/routes-transitions/package.json b/examples/routes-transitions/package.json index c61dd88174..59c5c79ca1 100644 --- a/examples/routes-transitions/package.json +++ b/examples/routes-transitions/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-routes-transitions", + "name": "example-routes-transitions", "dependencies": { "axios": "^0.15.3", "nuxt": "latest" diff --git a/examples/scroll-behavior/package.json b/examples/scroll-behavior/package.json index 2a869bb622..af16c90f04 100644 --- a/examples/scroll-behavior/package.json +++ b/examples/scroll-behavior/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-routes-transitions", + "name": "example-scroll-behavior", "dependencies": { "axios": "^0.15.3", "nuxt": "latest", diff --git a/examples/spa/package.json b/examples/spa/package.json index 92325ecf81..e9c67af966 100644 --- a/examples/spa/package.json +++ b/examples/spa/package.json @@ -1,5 +1,5 @@ { - "name": "hello-nuxt", + "name": "example-spa", "dependencies": { "nuxt": "latest" }, diff --git a/examples/static-images/package.json b/examples/static-images/package.json index 33d3b0501f..c81f68b36d 100644 --- a/examples/static-images/package.json +++ b/examples/static-images/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-hello-world", + "name": "example-static-images", "dependencies": { "nuxt": "latest" }, diff --git a/examples/storybook/package.json b/examples/storybook/package.json index 2aead00510..2fe78720e1 100644 --- a/examples/storybook/package.json +++ b/examples/storybook/package.json @@ -1,5 +1,5 @@ { - "name": "storybook", + "name": "example-storybook", "version": "1.0.0", "description": "sample storybook setup for nuxt", "scripts": { diff --git a/examples/style-resources/package.json b/examples/style-resources/package.json index 000d53f18f..5ff614e832 100644 --- a/examples/style-resources/package.json +++ b/examples/style-resources/package.json @@ -1,5 +1,5 @@ { - "name": "style-resources", + "name": "example-style-resources", "dependencies": { "less": "^2.7.3", "less-loader": "^4.0.5", diff --git a/examples/tailwindcss/package.json b/examples/tailwindcss/package.json index 11c1208cb1..4278286a1a 100644 --- a/examples/tailwindcss/package.json +++ b/examples/tailwindcss/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-tailwindcss", + "name": "example-tailwindcss", "description": "Nuxt.js with Tailwind CSS", "scripts": { "dev": "nuxt", diff --git a/examples/uikit/package.json b/examples/uikit/package.json index bc539ba586..54d25b924b 100644 --- a/examples/uikit/package.json +++ b/examples/uikit/package.json @@ -1,5 +1,5 @@ { - "name": "uikit-nuxt", + "name": "example-uikit", "dependencies": { "nuxt": "latest", "uikit": "^3.0.0-beta.30", diff --git a/examples/vue-apollo/package.json b/examples/vue-apollo/package.json index c9ffee9f88..4ae856ea88 100644 --- a/examples/vue-apollo/package.json +++ b/examples/vue-apollo/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-vue-apollo", + "name": "example-vue-apollo", "dependencies": { "@nuxtjs/apollo": "^2.1.1", "nuxt": "latest" diff --git a/examples/vue-chartjs/package.json b/examples/vue-chartjs/package.json index 90319704d1..19951c1123 100644 --- a/examples/vue-chartjs/package.json +++ b/examples/vue-chartjs/package.json @@ -1,5 +1,5 @@ { - "name": "vue-chartjs-nuxt", + "name": "example-vue-chartjs", "dependencies": { "axios": "^0.16.2", "chart.js": "^2.7.1", diff --git a/examples/vue-class-component/package.json b/examples/vue-class-component/package.json index 797a48f36e..0df6deda02 100644 --- a/examples/vue-class-component/package.json +++ b/examples/vue-class-component/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-class-component", + "name": "example-vue-class-component", "dependencies": { "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-decorators-legacy": "^1.3.4", diff --git a/examples/vuex-persistedstate/package.json b/examples/vuex-persistedstate/package.json index 5d9eef3ddf..d6088f8070 100644 --- a/examples/vuex-persistedstate/package.json +++ b/examples/vuex-persistedstate/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-vuex-store", + "name": "example-persisted-state", "dependencies": { "nuxt": "latest", "vuex-persistedstate": "^2.0.0" diff --git a/examples/vuex-store-modules/package.json b/examples/vuex-store-modules/package.json index 3bd4273fa4..b9fec7b13f 100644 --- a/examples/vuex-store-modules/package.json +++ b/examples/vuex-store-modules/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-vuex-store", + "name": "example-vuex-store-modules", "dependencies": { "nuxt": "latest" }, diff --git a/examples/vuex-store/package.json b/examples/vuex-store/package.json index 3bd4273fa4..c614964594 100644 --- a/examples/vuex-store/package.json +++ b/examples/vuex-store/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-vuex-store", + "name": "example-vuex-store", "dependencies": { "nuxt": "latest" }, diff --git a/examples/with-amp/package.json b/examples/with-amp/package.json index a9b129ca86..1d2244bbad 100644 --- a/examples/with-amp/package.json +++ b/examples/with-amp/package.json @@ -1,5 +1,5 @@ { - "name": "with-amp", + "name": "example-with-amp", "version": "1.0.0", "dependencies": { "nuxt": "latest" diff --git a/examples/with-ava/package.json b/examples/with-ava/package.json index 02065f4c57..bd3904771b 100755 --- a/examples/with-ava/package.json +++ b/examples/with-ava/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-with-ava", + "name": "example-with-ava", "scripts": { "dev": "nuxt", "build": "nuxt build", diff --git a/examples/with-ava/test/index.test.js b/examples/with-ava/test/index.test.js index 431f98f41f..971bccde38 100755 --- a/examples/with-ava/test/index.test.js +++ b/examples/with-ava/test/index.test.js @@ -8,16 +8,16 @@ import { Nuxt, Builder } from 'nuxt' let nuxt = null // Init Nuxt.js and create a server listening on localhost:4000 -test.before('Init Nuxt.js', async t => { +beforeAll(async () => { const rootDir = resolve(__dirname, '..') let config = {} try { config = require(resolve(rootDir, 'nuxt.config.js')) } catch (e) {} config.rootDir = rootDir // project folder config.dev = false // production build nuxt = new Nuxt(config) - await new Builder(nuxt).build() + new Builder(nuxt).build() await nuxt.listen(4000, 'localhost') -}) +}, 30000) // Example of testing only generated html test('Route / exits and render HTML', async t => { diff --git a/examples/with-buefy/package.json b/examples/with-buefy/package.json index cd44d6e878..d8969fd213 100644 --- a/examples/with-buefy/package.json +++ b/examples/with-buefy/package.json @@ -1,5 +1,5 @@ { - "name": "with-buefy", + "name": "example-with-buefy", "version": "1.0.0", "main": "index.js", "license": "MIT", diff --git a/examples/with-cookies/package.json b/examples/with-cookies/package.json index 17fc29e968..ab58fd3dac 100644 --- a/examples/with-cookies/package.json +++ b/examples/with-cookies/package.json @@ -1,5 +1,5 @@ { - "name": "hello-nuxt", + "name": "example-with-cookies", "dependencies": { "cookie": "^0.3.1", "js-cookie": "^2.1.4", diff --git a/examples/with-element-ui/package.json b/examples/with-element-ui/package.json index 40dc968f5b..97e2beacfd 100644 --- a/examples/with-element-ui/package.json +++ b/examples/with-element-ui/package.json @@ -1,5 +1,5 @@ { - "name": "with-element-ui", + "name": "example-with-element-ui", "version": "1.0.0", "license": "MIT", "dependencies": { diff --git a/examples/with-feathers/package.json b/examples/with-feathers/package.json index fc99464a7f..ada1686173 100644 --- a/examples/with-feathers/package.json +++ b/examples/with-feathers/package.json @@ -1,5 +1,5 @@ { - "name": "with-feathers", + "name": "example-with-feathers", "description": "Nuxt.js with FeathersJS", "version": "1.0.0", "main": "src/", diff --git a/examples/with-firebase/package.json b/examples/with-firebase/package.json index 99d0797aa6..7207064e23 100644 --- a/examples/with-firebase/package.json +++ b/examples/with-firebase/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-firebase", + "name": "example-with-firebase", "version": "1.0.0", "description": "Nuxt.js with Firebase", "scripts": { diff --git a/examples/with-keep-alive/package.json b/examples/with-keep-alive/package.json index eb09c6630e..adfaf8bf95 100644 --- a/examples/with-keep-alive/package.json +++ b/examples/with-keep-alive/package.json @@ -1,5 +1,5 @@ { - "name": "hello-nuxt-keep-alive", + "name": "example-with-keep-alive", "dependencies": { "nuxt": "latest" }, diff --git a/examples/with-museui/package.json b/examples/with-museui/package.json index 6f88ac897c..7eaef886d9 100644 --- a/examples/with-museui/package.json +++ b/examples/with-museui/package.json @@ -1,5 +1,5 @@ { - "name": "with-museui", + "name": "example-with-museui", "dependencies": { "nuxt": "latest", "muse-ui": "latest" diff --git a/examples/with-purgecss/package.json b/examples/with-purgecss/package.json index 538e7ca36f..72a0c82ea0 100644 --- a/examples/with-purgecss/package.json +++ b/examples/with-purgecss/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-tailwindcss", + "name": "example-with-purgecss", "description": "Nuxt.js with Tailwind CSS", "scripts": { "dev": "nuxt", diff --git a/examples/with-sockets/package.json b/examples/with-sockets/package.json index b29200ff34..5f82d28ef1 100644 --- a/examples/with-sockets/package.json +++ b/examples/with-sockets/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-socketio", + "name": "example-with-sockets", "scripts": { "dev": "nodemon -w server.js -w nuxt.config.js server.js", "build": "nuxt build", diff --git a/examples/with-tape/package.json b/examples/with-tape/package.json index afb974ee4a..6c2c56aeac 100755 --- a/examples/with-tape/package.json +++ b/examples/with-tape/package.json @@ -1,5 +1,5 @@ { - "name": "nuxt-with-tape", + "name": "example-with-tape", "scripts": { "dev": "nuxt", "build": "nuxt build", diff --git a/examples/with-vue-material/package.json b/examples/with-vue-material/package.json index 0363fc255b..b7e8306d7d 100644 --- a/examples/with-vue-material/package.json +++ b/examples/with-vue-material/package.json @@ -1,5 +1,5 @@ { - "name": "with-vue-material", + "name": "example-with-vue-material", "version": "1.0.0", "dependencies": { "nuxt": "latest", diff --git a/examples/with-vuetify/package.json b/examples/with-vuetify/package.json index 646947ae35..b7b176f153 100644 --- a/examples/with-vuetify/package.json +++ b/examples/with-vuetify/package.json @@ -1,5 +1,5 @@ { - "name": "with-vuetify", + "name": "example-with-vuetify", "dependencies": { "nuxt": "latest", "vuetify": "latest" diff --git a/examples/with-vux/package.json b/examples/with-vux/package.json index 7684d25bd7..844cd2cd98 100644 --- a/examples/with-vux/package.json +++ b/examples/with-vux/package.json @@ -1,5 +1,5 @@ { - "name": "with-vux", + "name": "example-with-vux", "version": "1.0.0", "license": "MIT", "dependencies": { diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000000..22d6ef094a --- /dev/null +++ b/jest.config.js @@ -0,0 +1,5 @@ +module.exports = { + testEnvironment: 'node', + coverageDirectory: './coverage/', + setupTestFrameworkScriptFile: './test/utils/setup' +} diff --git a/lib/builder/builder.mjs b/lib/builder/builder.mjs index 02060e9af7..091a05857a 100644 --- a/lib/builder/builder.mjs +++ b/lib/builder/builder.mjs @@ -40,6 +40,7 @@ export default class Builder { this.filesWatcher = null this.customFilesWatcher = null this.spinner = createSpinner() + this.spinner.enabled = !this.options.test // Mute stats on dev this.webpackStats = this.options.dev ? false : this.options.build.stats diff --git a/lib/builder/generator.mjs b/lib/builder/generator.mjs index 7e129cb750..3e3176f8c9 100644 --- a/lib/builder/generator.mjs +++ b/lib/builder/generator.mjs @@ -21,6 +21,7 @@ export default class Generator { ) this.spinner = createSpinner() + this.spinner.enabled = !this.options.test } async generate({ build = true, init = true } = {}) { diff --git a/lib/builder/webpack/base.config.mjs b/lib/builder/webpack/base.config.mjs index b867749206..44e4c3668b 100644 --- a/lib/builder/webpack/base.config.mjs +++ b/lib/builder/webpack/base.config.mjs @@ -1,5 +1,6 @@ import path from 'path' +import ExtractTextPlugin from 'extract-text-webpack-plugin' import FriendlyErrorsWebpackPlugin from '@nuxtjs/friendly-errors-webpack-plugin' import TimeFixPlugin from 'time-fix-plugin' import webpack from 'webpack' @@ -127,14 +128,16 @@ export default function webpackBaseConfig({ name, isServer }) { } // Build progress indicator - if (this.options.build.profile) { - config.plugins.push(new webpack.ProgressPlugin({ profile: true })) - } else { - config.plugins.push(new ProgressPlugin({ - spinner: this.spinner, - name: isServer ? 'server' : 'client', - color: isServer ? 'green' : 'darkgreen' - })) + if (!this.options.test) { + if (this.options.build.profile) { + config.plugins.push(new webpack.ProgressPlugin({ profile: true })) + } else { + config.plugins.push(new ProgressPlugin({ + spinner: this.spinner, + name: isServer ? 'server' : 'client', + color: isServer ? 'green' : 'darkgreen' + })) + } } // Add timefix-plugin before others plugins @@ -154,6 +157,22 @@ export default function webpackBaseConfig({ name, isServer }) { new FriendlyErrorsWebpackPlugin({ clearConsole: shouldClearConsole }) ) + // CSS extraction + const extractCSS = this.options.build.extractCSS + // TODO: Temporary disabled in dev mode for fixing source maps + // (We need `source-map` devtool for *.css modules) + if (extractCSS && !this.options.dev) { + config.plugins.push(new ExtractTextPlugin(Object.assign({ + filename: this.getFileName('css') + + // When using optimization.splitChunks and there are + // extracted chunks in the commons chunk, + // allChunks *must* be set to true + // TODO: For nuxt this makes duplicate css assets! + // allChunks: true + }, typeof extractCSS === 'object' ? extractCSS : {}))) + } + // Clone deep avoid leaking config between Client and Server return _.cloneDeep(config) } diff --git a/lib/builder/webpack/client.config.mjs b/lib/builder/webpack/client.config.mjs index 5219023d1a..d9d56f3971 100644 --- a/lib/builder/webpack/client.config.mjs +++ b/lib/builder/webpack/client.config.mjs @@ -2,8 +2,8 @@ import path from 'path' import _ from 'lodash' import webpack from 'webpack' + import HTMLPlugin from 'html-webpack-plugin' -import ExtractTextPlugin from 'extract-text-webpack-plugin' import StylishPlugin from 'webpack-stylish' import BundleAnalyzer from 'webpack-bundle-analyzer' @@ -119,25 +119,7 @@ export default function webpackClientConfig() { } // Create additional runtime chunk for cache boosting - // config.optimization.runtimeChunk = true - - // CSS extraction - const extractCSS = this.options.build.extractCSS - // TODO: Temporary disabled in dev mode for fixing source maps - // (We need `source-map` devtool for *.css modules) - if (extractCSS && !this.options.dev) { - config.plugins.push(new ExtractTextPlugin(Object.assign({ - filename: this.getFileName('css') - - // When using optimization.splitChunks and there are - // extracted chunks in the commons chunk, - // allChunks *must* be set to true - // TODO: For nuxt this makes duplicate css assets! - // allChunks: true - }, - typeof extractCSS === 'object' ? extractCSS : {} - ))) - } + config.optimization.runtimeChunk = true // -------------------------------------- // Dev specific config @@ -172,7 +154,7 @@ export default function webpackClientConfig() { } // https://github.com/webpack-contrib/webpack-stylish - if (!this.options.dev) { + if (!this.options.dev && !this.options.test) { config.plugins.push(new StylishPlugin()) } diff --git a/lib/common/nuxt.config.js b/lib/common/nuxt.config.js index db90aad66c..66fb24f63b 100644 --- a/lib/common/nuxt.config.js +++ b/lib/common/nuxt.config.js @@ -4,6 +4,7 @@ export default { mode: 'universal', dev: process.env.NODE_ENV !== 'production', debug: undefined, // Will be equal to dev if not provided + test: process.env.NODE_ENV === 'test', buildDir: '.nuxt', cacheDir: '.cache', nuxtDir: path.resolve(__dirname, '../..'), diff --git a/lib/common/utils.mjs b/lib/common/utils.mjs index 96730ab8c3..6980bac494 100644 --- a/lib/common/utils.mjs +++ b/lib/common/utils.mjs @@ -42,19 +42,6 @@ export const getContext = function getContext(req, res) { return { req, res } } -export const setAnsiColors = function setAnsiColors(ansiHTML) { - ansiHTML.setColors({ - reset: ['efefef', 'a6004c'], - darkgrey: '5a012b', - yellow: 'ffab07', - green: 'aeefba', - magenta: 'ff84bf', - blue: '3505a0', - cyan: '56eaec', - red: '4e053a' - }) -} - export const waitFor = function waitFor(ms) { return new Promise(resolve => setTimeout(resolve, ms || 0)) } @@ -133,8 +120,8 @@ export const parallel = function parallel(tasks, fn) { export const chainFn = function chainFn(base, fn) { /* istanbul ignore if */ - if (!(fn instanceof Function)) { - return + if (typeof fn !== 'function') { + return base } return function () { if (typeof base !== 'function') { diff --git a/lib/core/nuxt.mjs b/lib/core/nuxt.mjs index 15b3a5a1a9..870273f2a5 100644 --- a/lib/core/nuxt.mjs +++ b/lib/core/nuxt.mjs @@ -127,12 +127,14 @@ export default class Nuxt { } const _host = host === '0.0.0.0' ? 'localhost' : host - // eslint-disable-next-line no-console - console.log( - '\n' + + if (!this.options.test) { + // eslint-disable-next-line no-console + console.log( + '\n' + chalk.bgGreen.black(' OPEN ') + chalk.green(` http://${_host}:${port}\n`) - ) + ) + } // Close server on nuxt close this.hook( diff --git a/lib/core/renderer.mjs b/lib/core/renderer.mjs index ea2bb08f1f..0bf1063201 100644 --- a/lib/core/renderer.mjs +++ b/lib/core/renderer.mjs @@ -1,7 +1,6 @@ import path from 'path' import crypto from 'crypto' -import ansiHTML from 'ansi-html' import serialize from 'serialize-javascript' import serveStatic from 'serve-static' import compression from 'compression' @@ -12,7 +11,7 @@ import Debug from 'debug' import connect from 'connect' import launchMiddleware from 'launch-editor-middleware' -import { setAnsiColors, isUrl, waitFor, timeout } from '../common/utils' +import { isUrl, waitFor, timeout } from '../common/utils' import defaults from '../common/nuxt.config' import MetaRenderer from './meta' @@ -22,8 +21,6 @@ import nuxtMiddleware from './middleware/nuxt' const debug = Debug('nuxt:render') debug.color = 4 // Force blue color -setAnsiColors(ansiHTML) - let jsdom = null export default class Renderer { diff --git a/package.json b/package.json index 757ad26a78..d4210c221e 100644 --- a/package.json +++ b/package.json @@ -40,14 +40,12 @@ "bin": { "nuxt": "./bin/nuxt" }, - "nyc": { - "include": [ - "lib" - ] - }, "scripts": { - "test": "npm run lint && nyc ava -v test -- && nyc report --reporter=html", - "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov", + "test": "npm run build-fixtures && npm run test:unit", + "build-fixtures": "node ./scripts/build-fixtures", + "test:unit": "jest --maxWorkers=4 --coverage test/unit", + "test:e2e": "jest --maxWorkers=1 test/e2e", + "coverage": "codecov", "lint": "eslint --ext .js,.mjs,.vue bin/* build/ lib/ test/ examples/", "precommit": "npm run lint", "postinstall": "opencollective postinstall || exit 0" @@ -119,24 +117,27 @@ "webpack-stylish": "^0.1.6" }, "devDependencies": { - "ava": "^0.25.0", + "@expo/spawn-async": "^1.3.0", "babel-eslint": "^8.2.1", - "babel-plugin-istanbul": "^4.1.5", "codecov": "^3.0.0", "eslint": "^4.18.2", "eslint-config-standard": "^11.0.0", "eslint-config-standard-jsx": "^5.0.0", "eslint-plugin-html": "^4.0.2", "eslint-plugin-import": "^2.8.0", + "eslint-plugin-jest": "^21.15.0", "eslint-plugin-node": "^6.0.0", "eslint-plugin-promise": "^3.7.0", "eslint-plugin-react": "^7.6.1", "eslint-plugin-standard": "^3.0.1", "express": "^4.16.2", "finalhandler": "^1.1.1", + "get-port": "^3.2.0", + "jest": "^22.4.2", + "jest-runner-eslint": "^0.4.0", "jsdom": "^11.6.2", - "nyc": "^11.6.0", - "puppeteer": "^1.0.0", + "listr": "^0.13.0", + "puppeteer": "^1.2.0", "request": "^2.83.0", "request-promise-native": "^1.0.5", "sinon": "^4.4.5" diff --git a/scripts/build-fixtures b/scripts/build-fixtures new file mode 100755 index 0000000000..ff66ca97a7 --- /dev/null +++ b/scripts/build-fixtures @@ -0,0 +1,65 @@ +#!/usr/bin/env node +process.env.NODE_ENV = 'test' + +const { resolve } = require('path') +const { cpus } = require('os') + +const spawnAsync = require('@expo/spawn-async') +const Listr = require('listr') + +const fixtures = [ + 'children', + 'custom-dirs', + 'debug', + 'deprecate', + 'dynamic-routes', + 'empty', + 'error', + 'module', + 'ssr', + 'with-config', + + // csr, + // dev, + // generate, + // fail generate, + // fallback generate, + // ssr, + // ssr csp, + // spa + 'basic' +] + +const nuxtBuild = resolve(__dirname, '../bin/nuxt-build') + +function buildFixture(name) { + const rootDir = resolve(__dirname, '../test/fixtures', name) + return spawnAsync('node', [nuxtBuild, rootDir]) +} + +const tasks = [] +for (let fixture of fixtures) { + tasks.push({ + title: 'Building fixtures ' + fixture, + task: (ctx, task) => buildFixture(fixture) + .then(() => { + task.title = task.title.replace(/^Building/, 'Built') + ' Successfully' + }) + }) +} + +const options = { + renderer: process.env.CI ? 'silent' : 'default', + nonTTYRenderer: 'silent', + concurrent: Math.min(4, cpus().length) +} +new Listr([{ + title: `Build ${fixtures.length} fixtures with concurrency of ${options.concurrent}`, + task: () => new Listr(tasks, {concurrent: options.concurrent}) +}], options) + .run() + .then(() => process.exit(0)) + .catch((err) => { + console.error(err) // eslint-disable-line no-console + process.exit(1) + }) diff --git a/test/.babelrc b/test/.babelrc new file mode 100644 index 0000000000..3490fcb3f7 --- /dev/null +++ b/test/.babelrc @@ -0,0 +1,9 @@ +{ + "env": { + "test": { + "presets": [ + "env" + ] + } + } +} diff --git a/test/basic.config.defaults.test.js b/test/basic.config.defaults.test.js deleted file mode 100644 index efdb391a6f..0000000000 --- a/test/basic.config.defaults.test.js +++ /dev/null @@ -1,16 +0,0 @@ -import { resolve } from 'path' - -import test from 'ava' - -import { Nuxt, Options } from '..' -import { version } from '../package.json' - -test('Nuxt.version is same as package', t => { - t.is(Nuxt.version, version) -}) - -test('modulesDir uses /node_modules as default if not set', async t => { - const options = Options.from({}) - const currentNodeModulesDir = resolve(__dirname, '..', 'node_modules') - t.true(options.modulesDir.includes(currentNodeModulesDir)) -}) diff --git a/test/basic.csr.test.js b/test/basic.csr.test.js deleted file mode 100644 index 07363c0cf1..0000000000 --- a/test/basic.csr.test.js +++ /dev/null @@ -1,255 +0,0 @@ -import { resolve } from 'path' - -import test from 'ava' - -import { Nuxt, Builder } from '..' - -import * as browser from './helpers/browser' -import { interceptLog } from './helpers/console' - -const port = 4003 -const url = route => 'http://localhost:' + port + route - -let nuxt = null -let page = null - -const waitFor = ms => new Promise(resolve => setTimeout(resolve, ms || 0)) - -// Init nuxt.js and create server listening on localhost:4003 -test.serial('Init Nuxt.js', async t => { - const options = { - rootDir: resolve(__dirname, 'fixtures/basic'), - buildDir: '.nuxt-csr', - dev: true, - head: { - titleTemplate(titleChunk) { - return titleChunk ? `${titleChunk} - Nuxt.js` : 'Nuxt.js' - } - }, - build: { - stats: false - } - } - - const logSpy = await interceptLog(async () => { - nuxt = new Nuxt(options) - await new Builder(nuxt).build() - await nuxt.listen(port, 'localhost') - }) - - t.true(logSpy.calledWithMatch('DONE')) - t.true(logSpy.calledWithMatch('OPEN')) -}) - -test.serial('Start browser', async t => { - t.plan(0) // suppress 'no assertions' warning - await browser.start({ - // slowMo: 50, - // headless: false - }) -}) - -test.serial('Open /', async t => { - page = await browser.page(url('/')) - await waitFor(1000) - - t.is(await page.$text('h1'), 'Index page') -}) - -test.serial('/stateless', async t => { - const { hook } = await page.nuxt.navigate('/stateless', false) - const loading = await page.nuxt.loadingData() - await waitFor(1000) - - t.is(loading.show, true) - await hook - t.is(await page.$text('h1'), 'My component!') -}) - -test.serial('/css', async t => { - await page.nuxt.navigate('/css') - await waitFor(1000) - - t.is(await page.$text('.red'), 'This is red') - t.is( - await page.$eval('.red', red => window.getComputedStyle(red).color), - 'rgb(255, 0, 0)' - ) -}) - -test.serial('/stateful', async t => { - await page.nuxt.navigate('/stateful') - await waitFor(1000) - - t.is(await page.$text('p'), 'The answer is 42') -}) - -test.serial('/store', async t => { - await page.nuxt.navigate('/store') - await waitFor(1000) - - t.is(await page.$text('h1'), 'Vuex Nested Modules') - t.is(await page.$text('p'), '1') -}) - -test.serial('/head', async t => { - const msg = new Promise(resolve => - page.on('console', msg => resolve(msg.text())) - ) - await page.nuxt.navigate('/head') - const metas = await page.$$attr('meta', 'content') - await waitFor(1000) - - t.is(await msg, 'Body script!') - t.is(await page.title(), 'My title - Nuxt.js') - t.is(await page.$text('h1'), 'I can haz meta tags') - t.is(metas[0], 'my meta') -}) - -test.serial('/async-data', async t => { - await page.nuxt.navigate('/async-data') - await waitFor(1000) - - t.is(await page.$text('p'), 'Nuxt.js') -}) - -test.serial('/await-async-data', async t => { - await page.nuxt.navigate('/await-async-data') - await waitFor(1000) - - t.is(await page.$text('p'), 'Await Nuxt.js') -}) - -test.serial('/callback-async-data', async t => { - await page.nuxt.navigate('/callback-async-data') - await waitFor(1000) - - t.is(await page.$text('p'), 'Callback Nuxt.js') -}) - -test.serial('/users/1', async t => { - await page.nuxt.navigate('/users/1') - await waitFor(1000) - - t.is(await page.$text('h1'), 'User: 1') -}) - -test.serial('/validate should display a 404', async t => { - await page.nuxt.navigate('/validate') - await waitFor(1000) - - const error = await page.nuxt.errorData() - - t.is(error.statusCode, 404) - t.is(error.message, 'This page could not be found') -}) - -test.serial('/validate?valid=true', async t => { - await page.nuxt.navigate('/validate?valid=true') - await waitFor(1000) - - t.is(await page.$text('h1'), 'I am valid') -}) - -test.serial('/redirect', async t => { - await page.nuxt.navigate('/redirect') - await waitFor(1000) - - t.is(await page.$text('h1'), 'Index page') -}) - -test.serial('/error', async t => { - await page.nuxt.navigate('/error') - await waitFor(1000) - - t.deepEqual(await page.nuxt.errorData(), { statusCode: 500 }) - t.is(await page.$text('.title'), 'Error mouahahah') -}) - -test.serial('/error2', async t => { - await page.nuxt.navigate('/error2') - await waitFor(1000) - - t.is(await page.$text('.title'), 'Custom error') - t.deepEqual(await page.nuxt.errorData(), { message: 'Custom error' }) -}) - -test.serial('/redirect-middleware', async t => { - await page.nuxt.navigate('/redirect-middleware') - await waitFor(1000) - - t.is(await page.$text('h1'), 'Index page') -}) - -test.serial('/redirect-external', async t => { - // New page for redirecting to external link. - const page = await browser.page(url('/')) - - await page.nuxt.navigate('/redirect-external', false) - await waitFor(1000) - - await page.waitForFunction( - () => window.location.href === 'https://nuxtjs.org/' - ) - page.close() - t.pass() -}) - -test.serial('/redirect-name', async t => { - await page.nuxt.navigate('/redirect-name') - await waitFor(1000) - - t.is(await page.$text('h1'), 'My component!') -}) - -test.serial('/no-ssr', async t => { - await page.nuxt.navigate('/no-ssr') - await waitFor(1000) - - t.is(await page.$text('h1'), 'Displayed only on client-side') -}) - -test.serial('/meta', async t => { - await page.nuxt.navigate('/meta') - await waitFor(1000) - - const state = await page.nuxt.storeState() - t.deepEqual(state.meta, [{ works: true }]) -}) - -test.serial('/fn-midd', async t => { - await page.nuxt.navigate('/fn-midd') - await waitFor(1000) - - t.is(await page.$text('.title'), 'You need to ask the permission') - t.deepEqual(await page.nuxt.errorData(), { - message: 'You need to ask the permission', - statusCode: 403 - }) -}) - -test.serial('/fn-midd?please=true', async t => { - await page.nuxt.navigate('/fn-midd?please=true') - await waitFor(1000) - - const h1 = await page.$text('h1') - t.true(h1.includes('Date:')) -}) - -test.serial('/router-guard', async t => { - await page.nuxt.navigate('/router-guard') - await waitFor(1000) - - const p = await page.$text('p') - t.is(p, 'Nuxt.js') -}) - -test.after.always('Stop browser', async () => { - process.on('unhandledRejection', () => {}) - await browser.stop() -}) - -// Close server and ask nuxt to stop listening to file changes -test.after.always('Closing server and nuxt.js', async () => { - await nuxt.close() -}) diff --git a/test/basic.dev.test.js b/test/basic.dev.test.js deleted file mode 100644 index 5ebbdbd96c..0000000000 --- a/test/basic.dev.test.js +++ /dev/null @@ -1,67 +0,0 @@ -import test from 'ava' -import { resolve } from 'path' -import { intercept, release } from './helpers/console' -import { Nuxt, Builder } from '..' - -const port = 4001 -const url = route => 'http://localhost:' + port + route -const rootDir = resolve(__dirname, 'fixtures/basic') - -let nuxt = null - -// Init nuxt.js and create server listening on localhost:4000 -test.serial('Init Nuxt.js', async t => { - const options = { - rootDir, - buildDir: '.nuxt-dev', - dev: true, - build: { - stats: false, - profile: true, - extractCSS: { - allChunks: true - } - } - } - - const spies = await intercept({ log: true, stderr: true }, async () => { - nuxt = new Nuxt(options) - await new Builder(nuxt).build() - await nuxt.listen(port, 'localhost') - }) - - t.true(spies.log.calledWithMatch('DONE')) - t.true(spies.log.calledWithMatch('OPEN')) -}) - -// TODO: enable test when style-loader.js:60 was resolved -// test.serial('/extractCSS', async t => { -// const window = await nuxt.renderAndGetWindow(url('/extractCSS')) -// const html = window.document.head.innerHTML -// t.true(html.includes('vendor.css')) -// t.true(!html.includes('30px')) -// t.is(window.getComputedStyle(window.document.body).getPropertyValue('font-size'), '30px') -// }) - -test.serial('/stateless', async t => { - const spies = await intercept() - const window = await nuxt.renderAndGetWindow(url('/stateless')) - const html = window.document.body.innerHTML - t.true(html.includes('

My component!

')) - t.true(spies.info.calledWithMatch('You are running Vue in development mode.')) - release() -}) - -// test('/_nuxt/test.hot-update.json should returns empty html', async t => { -// try { -// await rp(url('/_nuxt/test.hot-update.json')) -// } catch (err) { -// t.is(err.statusCode, 404) -// t.is(err.response.body, '') -// } -// }) - -// Close server and ask nuxt to stop listening to file changes -test.after.always('Closing server and nuxt.js', async t => { - await nuxt.close() -}) diff --git a/test/basic.fail.generate.test.js b/test/basic.fail.generate.test.js deleted file mode 100644 index 606e2dbd9c..0000000000 --- a/test/basic.fail.generate.test.js +++ /dev/null @@ -1,34 +0,0 @@ -import { resolve } from 'path' - -import test from 'ava' - -import { Nuxt, Builder, Generator } from '..' - -import { intercept } from './helpers/console' - -test('Fail with routes() which throw an error', async t => { - const options = { - rootDir: resolve(__dirname, 'fixtures/basic'), - buildDir: '.nuxt-fail', - dev: false, - build: { - stats: false - }, - generate: { - async routes() { - throw new Error('Not today!') - } - } - } - const spies = await intercept(async () => { - const nuxt = new Nuxt(options) - const builder = new Builder(nuxt) - const generator = new Generator(nuxt, builder) - - return generator.generate().catch(e => { - t.true(e.message === 'Not today!') - }) - }) - t.true(spies.log.calledWithMatch('DONE')) - t.true(spies.error.withArgs('Could not resolve routes').calledOnce) -}) diff --git a/test/basic.generate.test.js b/test/basic.generate.test.js deleted file mode 100644 index cd2a4cc494..0000000000 --- a/test/basic.generate.test.js +++ /dev/null @@ -1,190 +0,0 @@ -import { existsSync } from 'fs' -import http from 'http' -import { resolve } from 'path' - -import test from 'ava' -import { remove } from 'fs-extra' -import serveStatic from 'serve-static' -import finalhandler from 'finalhandler' -import rp from 'request-promise-native' - -import { Nuxt, Builder, Generator } from '..' - -import { interceptLog, release } from './helpers/console' -import { loadConfig } from './helpers/config' - -const port = 4002 -const url = route => 'http://localhost:' + port + route -const rootDir = resolve(__dirname, 'fixtures/basic') - -let nuxt = null -let server = null -let generator = null - -// Init nuxt.js and create server listening on localhost:4000 -test.serial('Init Nuxt.js', async t => { - const config = loadConfig('basic', { - buildDir: '.nuxt-generate', - dev: false - }) - - config.build.stats = false - - const logSpy = await interceptLog(async () => { - nuxt = new Nuxt(config) - const builder = new Builder(nuxt) - generator = new Generator(nuxt, builder) - - await generator.generate() - }) - t.true(logSpy.calledWithMatch('DONE')) - - const serve = serveStatic(resolve(__dirname, 'fixtures/basic/dist')) - server = http.createServer((req, res) => { - serve(req, res, finalhandler(req, res)) - }) - server.listen(port) -}) - -test.serial('Check ready hook called', async t => { - t.true(nuxt.__hook_called__) -}) - -test.serial('/stateless', async t => { - const window = await nuxt.renderAndGetWindow(url('/stateless')) - const html = window.document.body.innerHTML - t.true(html.includes('

My component!

')) -}) - -test.serial('/css', async t => { - const window = await nuxt.renderAndGetWindow(url('/css')) - - const headHtml = window.document.head.innerHTML - t.true(headHtml.includes('.red{color:red}')) - - const element = window.document.querySelector('.red') - t.not(element, null) - t.is(element.textContent, 'This is red') - t.is(element.className, 'red') - // t.is(window.getComputedStyle(element), 'red') -}) - -test.serial('/stateful', async t => { - const window = await nuxt.renderAndGetWindow(url('/stateful')) - const html = window.document.body.innerHTML - t.true(html.includes('

The answer is 42

')) -}) - -test.serial('/head', async t => { - const logSpy = await interceptLog() - const window = await nuxt.renderAndGetWindow(url('/head')) - const html = window.document.body.innerHTML - const metas = window.document.getElementsByTagName('meta') - t.is(window.document.title, 'My title') - t.is(metas[0].getAttribute('content'), 'my meta') - t.true(html.includes('

I can haz meta tags

')) - release() - t.is(logSpy.getCall(0).args[0], 'Body script!') -}) - -test.serial('/async-data', async t => { - const window = await nuxt.renderAndGetWindow(url('/async-data')) - const html = window.document.body.innerHTML - t.true(html.includes('

Nuxt.js

')) -}) - -test.serial('/users/1/index.html', async t => { - const html = await rp(url('/users/1/index.html')) - t.true(html.includes('

User: 1

')) - t.true( - existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1/index.html')) - ) - t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1.html'))) -}) - -test.serial('/users/2', async t => { - const html = await rp(url('/users/2')) - t.true(html.includes('

User: 2

')) -}) - -test.serial('/users/3 (payload given)', async t => { - const html = await rp(url('/users/3')) - t.true(html.includes('

User: 3000

')) -}) - -test.serial('/users/4 -> Not found', async t => { - const error = await t.throws(rp(url('/users/4'))) - t.true(error.statusCode === 404) - t.true(error.response.body.includes('Cannot GET /users/4')) -}) - -test.serial('/validate should not be server-rendered', async t => { - const html = await rp(url('/validate')) - t.true(html.includes('
')) - t.true(html.includes('serverRendered:!1')) -}) - -test.serial('/validate -> should display a 404', async t => { - const window = await nuxt.renderAndGetWindow(url('/validate')) - const html = window.document.body.innerHTML - t.true(html.includes('This page could not be found')) -}) - -test.serial('/validate?valid=true', async t => { - const window = await nuxt.renderAndGetWindow(url('/validate?valid=true')) - const html = window.document.body.innerHTML - t.true(html.includes('I am valid')) -}) - -test.serial('/redirect should not be server-rendered', async t => { - const html = await rp(url('/redirect')) - t.true(html.includes('
')) - t.true(html.includes('serverRendered:!1')) -}) - -test.serial('/redirect -> check redirected source', async t => { - const window = await nuxt.renderAndGetWindow(url('/redirect')) - const html = window.document.body.innerHTML - t.true(html.includes('

Index page

')) -}) - -test.serial('/users/1 not found', async t => { - await remove(resolve(rootDir, 'dist/users')) - const error = await t.throws(rp(url('/users/1'))) - t.true(error.statusCode === 404) - t.true(error.response.body.includes('Cannot GET /users/1')) -}) - -test.serial('nuxt re-generating with no subfolders', async t => { - const logSpy = await interceptLog() - nuxt.options.generate.subFolders = false - await generator.generate() - release() - t.true(logSpy.calledWithMatch('DONE')) -}) - -test.serial('/users/1.html', async t => { - const html = await rp(url('/users/1.html')) - t.true(html.includes('

User: 1

')) - t.true(existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1.html'))) - t.false( - existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1/index.html')) - ) -}) - -test.serial('/-ignored', async t => { - const error = await t.throws(rp(url('/-ignored'))) - t.true(error.statusCode === 404) - t.true(error.response.body.includes('Cannot GET /-ignored')) -}) - -test.serial('/ignored.test', async t => { - const error = await t.throws(rp(url('/ignored.test'))) - t.true(error.statusCode === 404) - t.true(error.response.body.includes('Cannot GET /ignored.test')) -}) - -// Close server and ask nuxt to stop listening to file changes -test.after.always('Closing server', async t => { - await server.close() -}) diff --git a/test/basic.ssr.csp.test.js b/test/basic.ssr.csp.test.js deleted file mode 100644 index 471e46a258..0000000000 --- a/test/basic.ssr.csp.test.js +++ /dev/null @@ -1,125 +0,0 @@ -import { resolve } from 'path' - -import test from 'ava' -import rp from 'request-promise-native' - -import { Nuxt, Builder } from '..' - -import { interceptLog } from './helpers/console' - -const port = 4005 -const url = route => 'http://localhost:' + port + route - -// Init nuxt.js and create server listening on localhost:4005 -const startCSPTestServer = async (t, csp) => { - const options = { - rootDir: resolve(__dirname, 'fixtures/basic'), - buildDir: '.nuxt-ssr-csp', - dev: false, - head: { - titleTemplate(titleChunk) { - return titleChunk ? `${titleChunk} - Nuxt.js` : 'Nuxt.js' - } - }, - build: { stats: false }, - render: { csp } - } - - let nuxt = null - const logSpy = await interceptLog(async () => { - nuxt = new Nuxt(options) - const builder = await new Builder(nuxt) - await builder.build() - await nuxt.listen(port, '0.0.0.0') - }) - - t.true(logSpy.calledWithMatch('DONE')) - t.true(logSpy.calledWithMatch('OPEN')) - - return nuxt -} - -test.serial('Not contain Content-Security-Policy header, when csp.enabled is not set', async t => { - const nuxt = await startCSPTestServer(t, {}) - const { headers } = await rp(url('/stateless'), { - resolveWithFullResponse: true - }) - - t.is(headers['content-security-policy'], undefined) - - await nuxt.close() -}) - -test.serial('Contain Content-Security-Policy header, when csp.enabled is only set', async t => { - const cspOption = { - enabled: true - } - - const nuxt = await startCSPTestServer(t, cspOption) - const { headers } = await rp(url('/stateless'), { - resolveWithFullResponse: true - }) - - t.regex(headers['content-security-policy'], /^script-src 'self' 'sha256-.*'$/) - - await nuxt.close() -}) - -test.serial('Contain Content-Security-Policy header, when csp.allowedSources set', async t => { - const cspOption = { - enabled: true, - allowedSources: ['https://example.com', 'https://example.io'] - } - - const nuxt = await startCSPTestServer(t, cspOption) - const { headers } = await rp(url('/stateless'), { - resolveWithFullResponse: true - }) - - t.regex(headers['content-security-policy'], /^script-src 'self' 'sha256-.*'/) - t.true(headers['content-security-policy'].includes('https://example.com')) - t.true(headers['content-security-policy'].includes('https://example.io')) - - await nuxt.close() -}) - -test.serial('Contain Content-Security-Policy header, when csp.policies set', async t => { - const cspOption = { - enabled: true, - policies: { - 'default-src': [`'none'`], - 'script-src': ['https://example.com', 'https://example.io'] - } - } - - const nuxt = await startCSPTestServer(t, cspOption) - const { headers } = await rp(url('/stateless'), { - resolveWithFullResponse: true - }) - - t.regex(headers['content-security-policy'], /default-src 'none'/) - t.regex(headers['content-security-policy'], /script-src 'self' 'sha256-.*'/) - t.true(headers['content-security-policy'].includes('https://example.com')) - t.true(headers['content-security-policy'].includes('https://example.io')) - - await nuxt.close() -}) - -test.serial('Contain Content-Security-Policy header, when csp.policies.script-src is not set', async t => { - const cspOption = { - enabled: true, - policies: { - 'default-src': [`'none'`] - } - } - - const nuxt = await startCSPTestServer(t, cspOption) - const { headers } = await rp(url('/stateless'), { - resolveWithFullResponse: true - }) - - t.regex(headers['content-security-policy'], /default-src 'none'/) - t.regex(headers['content-security-policy'], /script-src 'self' 'sha256-.*'/) - - await nuxt.close() -}) diff --git a/test/basic.ssr.test.js b/test/basic.ssr.test.js deleted file mode 100644 index 1d4415e73c..0000000000 --- a/test/basic.ssr.test.js +++ /dev/null @@ -1,312 +0,0 @@ -import { resolve } from 'path' - -import test from 'ava' -import rp from 'request-promise-native' - -import { Nuxt, Builder } from '..' - -import { interceptLog, interceptError, release } from './helpers/console' - -const port = 4004 -const url = route => 'http://localhost:' + port + route - -let nuxt = null - -// Init nuxt.js and create server listening on localhost:4004 -test.serial('Init Nuxt.js', async t => { - const options = { - rootDir: resolve(__dirname, 'fixtures/basic'), - buildDir: '.nuxt-ssr', - dev: false, - head: { - titleTemplate(titleChunk) { - return titleChunk ? `${titleChunk} - Nuxt.js` : 'Nuxt.js' - } - }, - build: { - stats: false - } - } - - const logSpy = await interceptLog(async () => { - nuxt = new Nuxt(options) - const builder = await new Builder(nuxt) - await builder.build() - await nuxt.listen(port, '0.0.0.0') - }) - - t.true(logSpy.calledWithMatch('DONE')) - t.true(logSpy.calledWithMatch('OPEN')) -}) - -test('/stateless', async t => { - const { html } = await nuxt.renderRoute('/stateless') - t.true(html.includes('

My component!

')) -}) - -/* -** Example of testing via dom checking -*/ -test('/css', async t => { - const window = await nuxt.renderAndGetWindow(url('/css')) - - const headHtml = window.document.head.innerHTML - t.true(headHtml.includes('color:red')) - - const element = window.document.querySelector('.red') - t.not(element, null) - t.is(element.textContent, 'This is red') - t.is(element.className, 'red') - // t.is(window.getComputedStyle(element).color, 'red') -}) - -test('/postcss', async t => { - const window = await nuxt.renderAndGetWindow(url('/css')) - - const headHtml = window.document.head.innerHTML - t.true(headHtml.includes('background-color:blue')) - - // const element = window.document.querySelector('div.red') - // t.is(window.getComputedStyle(element)['background-color'], 'blue') -}) - -test('/stateful', async t => { - const { html } = await nuxt.renderRoute('/stateful') - t.true(html.includes('

The answer is 42

')) -}) - -test('/store', async t => { - const { html } = await nuxt.renderRoute('/store') - t.true(html.includes('

Vuex Nested Modules

')) - t.true(html.includes('

1

')) -}) - -test.serial('/head', async t => { - const logSpy = await interceptLog() - const window = await nuxt.renderAndGetWindow(url('/head'), { - virtualConsole: false - }) - t.is(window.document.title, 'My title - Nuxt.js') - - const html = window.document.body.innerHTML - t.true(html.includes('

I can haz meta tags

')) - t.true( - html.includes('