mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 16:12:12 +00:00
Merge pull request #3052 from nuxt/feat/jest
feat: migrate testing tool to jest
This commit is contained in:
commit
9c8837d52b
@ -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
|
||||
|
@ -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': {
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "components-injection-nuxt",
|
||||
"name": "example-async-components-injection",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-async-data",
|
||||
"name": "example-async-data",
|
||||
"dependencies": {
|
||||
"axios": "latest",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "auth-routes",
|
||||
"name": "example-auth-routes",
|
||||
"dependencies": {
|
||||
"axios": "^0.16.1",
|
||||
"body-parser": "^1.17.2",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-proxy",
|
||||
"name": "example-axios",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@nuxtjs/axios": "^5.0.0",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-cached-components",
|
||||
"name": "example-cached-components",
|
||||
"dependencies": {
|
||||
"lru-cache": "^4.0.2",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "coffeescript",
|
||||
"name": "example-coffeescript",
|
||||
"version": "1.0.0",
|
||||
"description": "Nuxt.js with CoffeeScript",
|
||||
"author": "Alex Ananiev <alex.ananiev.r@gmail.com>",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-custom-build",
|
||||
"name": "example-custom-build",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-custom-layouts",
|
||||
"name": "example-custom-layouts",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-custom-loading",
|
||||
"name": "example-custom-loading",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-custom-routes",
|
||||
"name": "example-custom-routes",
|
||||
"dependencies": {
|
||||
"axios": "latest",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-custom-server",
|
||||
"name": "example-custom-server",
|
||||
"dependencies": {
|
||||
"express": "^4.15.3",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "dynamic-components-nuxt",
|
||||
"name": "example-dynamic-components",
|
||||
"dependencies": {
|
||||
"chart.js": "^2.7.0",
|
||||
"nuxt": "latest",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-dynamic-layouts",
|
||||
"name": "example-dynamic-layouts",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-global-css",
|
||||
"name": "example-global-css",
|
||||
"dependencies": {
|
||||
"bulma": "^0.5.1",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "hello-nuxt",
|
||||
"name": "example-hello-world",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-i18n",
|
||||
"name": "example-i18n",
|
||||
"dependencies": {
|
||||
"nuxt": "latest",
|
||||
"vue-i18n": "^7.3.2"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-jsx",
|
||||
"name": "example-jsx",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-layout-transitions",
|
||||
"name": "example-layout-transitions",
|
||||
"dependencies": {
|
||||
"axios": "^0.15.3",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-markdownit",
|
||||
"name": "example-markdownit",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@nuxtjs/markdownit": "^1.1.2",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-head-elements",
|
||||
"name": "example-meta-info",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-middleware",
|
||||
"name": "example-middleware",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-nested-components",
|
||||
"name": "example-nested-components",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-nested-routes",
|
||||
"name": "example-nested-routes",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "no-ssr-cmp-nuxt",
|
||||
"name": "example-no-ssr",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-plugins-vendor",
|
||||
"name": "example-plugins-vendor",
|
||||
"dependencies": {
|
||||
"axios": "^0.16.2",
|
||||
"mini-toastr": "^0.6.5",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-routes-transitions",
|
||||
"name": "example-routes-transitions",
|
||||
"dependencies": {
|
||||
"axios": "^0.15.3",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-routes-transitions",
|
||||
"name": "example-scroll-behavior",
|
||||
"dependencies": {
|
||||
"axios": "^0.15.3",
|
||||
"nuxt": "latest",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "hello-nuxt",
|
||||
"name": "example-spa",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-hello-world",
|
||||
"name": "example-static-images",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "storybook",
|
||||
"name": "example-storybook",
|
||||
"version": "1.0.0",
|
||||
"description": "sample storybook setup for nuxt",
|
||||
"scripts": {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "style-resources",
|
||||
"name": "example-style-resources",
|
||||
"dependencies": {
|
||||
"less": "^2.7.3",
|
||||
"less-loader": "^4.0.5",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-tailwindcss",
|
||||
"name": "example-tailwindcss",
|
||||
"description": "Nuxt.js with Tailwind CSS",
|
||||
"scripts": {
|
||||
"dev": "nuxt",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "uikit-nuxt",
|
||||
"name": "example-uikit",
|
||||
"dependencies": {
|
||||
"nuxt": "latest",
|
||||
"uikit": "^3.0.0-beta.30",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-vue-apollo",
|
||||
"name": "example-vue-apollo",
|
||||
"dependencies": {
|
||||
"@nuxtjs/apollo": "^2.1.1",
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "vue-chartjs-nuxt",
|
||||
"name": "example-vue-chartjs",
|
||||
"dependencies": {
|
||||
"axios": "^0.16.2",
|
||||
"chart.js": "^2.7.1",
|
||||
|
@ -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",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-vuex-store",
|
||||
"name": "example-persisted-state",
|
||||
"dependencies": {
|
||||
"nuxt": "latest",
|
||||
"vuex-persistedstate": "^2.0.0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-vuex-store",
|
||||
"name": "example-vuex-store-modules",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-vuex-store",
|
||||
"name": "example-vuex-store",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-amp",
|
||||
"name": "example-with-amp",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-with-ava",
|
||||
"name": "example-with-ava",
|
||||
"scripts": {
|
||||
"dev": "nuxt",
|
||||
"build": "nuxt build",
|
||||
|
@ -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 => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-buefy",
|
||||
"name": "example-with-buefy",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "hello-nuxt",
|
||||
"name": "example-with-cookies",
|
||||
"dependencies": {
|
||||
"cookie": "^0.3.1",
|
||||
"js-cookie": "^2.1.4",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-element-ui",
|
||||
"name": "example-with-element-ui",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-feathers",
|
||||
"name": "example-with-feathers",
|
||||
"description": "Nuxt.js with FeathersJS",
|
||||
"version": "1.0.0",
|
||||
"main": "src/",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-firebase",
|
||||
"name": "example-with-firebase",
|
||||
"version": "1.0.0",
|
||||
"description": "Nuxt.js with Firebase",
|
||||
"scripts": {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "hello-nuxt-keep-alive",
|
||||
"name": "example-with-keep-alive",
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-museui",
|
||||
"name": "example-with-museui",
|
||||
"dependencies": {
|
||||
"nuxt": "latest",
|
||||
"muse-ui": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-tailwindcss",
|
||||
"name": "example-with-purgecss",
|
||||
"description": "Nuxt.js with Tailwind CSS",
|
||||
"scripts": {
|
||||
"dev": "nuxt",
|
||||
|
@ -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",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nuxt-with-tape",
|
||||
"name": "example-with-tape",
|
||||
"scripts": {
|
||||
"dev": "nuxt",
|
||||
"build": "nuxt build",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-vue-material",
|
||||
"name": "example-with-vue-material",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"nuxt": "latest",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-vuetify",
|
||||
"name": "example-with-vuetify",
|
||||
"dependencies": {
|
||||
"nuxt": "latest",
|
||||
"vuetify": "latest"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "with-vux",
|
||||
"name": "example-with-vux",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
5
jest.config.js
Normal file
5
jest.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
testEnvironment: 'node',
|
||||
coverageDirectory: './coverage/',
|
||||
setupTestFrameworkScriptFile: './test/utils/setup'
|
||||
}
|
@ -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
|
||||
|
@ -21,6 +21,7 @@ export default class Generator {
|
||||
)
|
||||
|
||||
this.spinner = createSpinner()
|
||||
this.spinner.enabled = !this.options.test
|
||||
}
|
||||
|
||||
async generate({ build = true, init = true } = {}) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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, '../..'),
|
||||
|
@ -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') {
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
23
package.json
23
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"
|
||||
|
65
scripts/build-fixtures
Executable file
65
scripts/build-fixtures
Executable file
@ -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)
|
||||
})
|
9
test/.babelrc
Normal file
9
test/.babelrc
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": [
|
||||
"env"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -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))
|
||||
})
|
@ -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()
|
||||
})
|
@ -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('<h1>My component!</h1>'))
|
||||
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()
|
||||
})
|
@ -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)
|
||||
})
|
@ -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('<h1>My component!</h1>'))
|
||||
})
|
||||
|
||||
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('<div><p>The answer is 42</p></div>'))
|
||||
})
|
||||
|
||||
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('<div><h1>I can haz meta tags</h1></div>'))
|
||||
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('<p>Nuxt.js</p>'))
|
||||
})
|
||||
|
||||
test.serial('/users/1/index.html', async t => {
|
||||
const html = await rp(url('/users/1/index.html'))
|
||||
t.true(html.includes('<h1>User: 1</h1>'))
|
||||
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('<h1>User: 2</h1>'))
|
||||
})
|
||||
|
||||
test.serial('/users/3 (payload given)', async t => {
|
||||
const html = await rp(url('/users/3'))
|
||||
t.true(html.includes('<h1>User: 3000</h1>'))
|
||||
})
|
||||
|
||||
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('<div id="__nuxt"></div>'))
|
||||
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</h1>'))
|
||||
})
|
||||
|
||||
test.serial('/redirect should not be server-rendered', async t => {
|
||||
const html = await rp(url('/redirect'))
|
||||
t.true(html.includes('<div id="__nuxt"></div>'))
|
||||
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('<h1>Index page</h1>'))
|
||||
})
|
||||
|
||||
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('<h1>User: 1</h1>'))
|
||||
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()
|
||||
})
|
@ -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()
|
||||
})
|
@ -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('<h1>My component!</h1>'))
|
||||
})
|
||||
|
||||
/*
|
||||
** 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('<div><p>The answer is 42</p></div>'))
|
||||
})
|
||||
|
||||
test('/store', async t => {
|
||||
const { html } = await nuxt.renderRoute('/store')
|
||||
t.true(html.includes('<h1>Vuex Nested Modules</h1>'))
|
||||
t.true(html.includes('<p>1</p>'))
|
||||
})
|
||||
|
||||
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('<div><h1>I can haz meta tags</h1></div>'))
|
||||
t.true(
|
||||
html.includes('<script data-n-head="true" src="/body.js" data-body="true">')
|
||||
)
|
||||
|
||||
const metas = window.document.getElementsByTagName('meta')
|
||||
t.is(metas[0].getAttribute('content'), 'my meta')
|
||||
release()
|
||||
|
||||
t.true(logSpy.calledOnce)
|
||||
t.is(logSpy.args[0][0], 'Body script!')
|
||||
})
|
||||
|
||||
test('/async-data', async t => {
|
||||
const { html } = await nuxt.renderRoute('/async-data')
|
||||
t.true(html.includes('<p>Nuxt.js</p>'))
|
||||
})
|
||||
|
||||
test('/await-async-data', async t => {
|
||||
const { html } = await nuxt.renderRoute('/await-async-data')
|
||||
t.true(html.includes('<p>Await Nuxt.js</p>'))
|
||||
})
|
||||
|
||||
test('/callback-async-data', async t => {
|
||||
const { html } = await nuxt.renderRoute('/callback-async-data')
|
||||
t.true(html.includes('<p>Callback Nuxt.js</p>'))
|
||||
})
|
||||
|
||||
test('/users/1', async t => {
|
||||
const { html } = await nuxt.renderRoute('/users/1')
|
||||
t.true(html.includes('<h1>User: 1</h1>'))
|
||||
})
|
||||
|
||||
test('/validate should display a 404', async t => {
|
||||
const { html } = await nuxt.renderRoute('/validate')
|
||||
t.true(html.includes('This page could not be found'))
|
||||
})
|
||||
|
||||
test('/validate?valid=true', async t => {
|
||||
const { html } = await nuxt.renderRoute('/validate?valid=true')
|
||||
t.true(html.includes('<h1>I am valid</h1>'))
|
||||
})
|
||||
|
||||
test('/redirect', async t => {
|
||||
const { html, redirected } = await nuxt.renderRoute('/redirect')
|
||||
t.true(html.includes('<div id="__nuxt"></div>'))
|
||||
t.true(redirected.path === '/')
|
||||
t.true(redirected.status === 302)
|
||||
})
|
||||
|
||||
test('/redirect -> check redirected source', async t => {
|
||||
// there are no transition properties in jsdom, ignore the error log
|
||||
await interceptError()
|
||||
const window = await nuxt.renderAndGetWindow(url('/redirect'))
|
||||
release()
|
||||
const html = window.document.body.innerHTML
|
||||
t.true(html.includes('<h1>Index page</h1>'))
|
||||
})
|
||||
|
||||
test('/redirect -> external link', async t => {
|
||||
let _headers, _status
|
||||
const { html } = await nuxt.renderRoute('/redirect-external', {
|
||||
res: {
|
||||
writeHead(status, headers) {
|
||||
_status = status
|
||||
_headers = headers
|
||||
},
|
||||
end() {}
|
||||
}
|
||||
})
|
||||
t.is(_status, 302)
|
||||
t.is(_headers.Location, 'https://nuxtjs.org')
|
||||
t.true(html.includes('<div data-server-rendered="true"></div>'))
|
||||
})
|
||||
|
||||
test('/special-state -> check window.__NUXT__.test = true', async t => {
|
||||
const window = await nuxt.renderAndGetWindow(url('/special-state'))
|
||||
t.is(window.document.title, 'Nuxt.js')
|
||||
t.is(window.__NUXT__.test, true)
|
||||
})
|
||||
|
||||
test('/error', async t => {
|
||||
const err = await t.throws(nuxt.renderRoute('/error', { req: {}, res: {} }))
|
||||
t.true(err.message.includes('Error mouahahah'))
|
||||
})
|
||||
|
||||
test.serial('/error status code', async t => {
|
||||
const errorSpy = await interceptError()
|
||||
const err = await t.throws(rp(url('/error')))
|
||||
t.true(err.statusCode === 500)
|
||||
t.true(
|
||||
err.response.body.includes(
|
||||
'An error occurred in the application and your page could not be served'
|
||||
)
|
||||
)
|
||||
release()
|
||||
t.true(errorSpy.calledOnce)
|
||||
t.true(errorSpy.args[0][0].message.includes('Error mouahahah'))
|
||||
})
|
||||
|
||||
test('/error2', async t => {
|
||||
const { html, error } = await nuxt.renderRoute('/error2')
|
||||
t.true(html.includes('Custom error'))
|
||||
t.true(error.message.includes('Custom error'))
|
||||
t.true(error.statusCode === undefined)
|
||||
})
|
||||
|
||||
test('/error2 status code', async t => {
|
||||
const error = await t.throws(rp(url('/error2')))
|
||||
t.is(error.statusCode, 500)
|
||||
t.true(error.response.body.includes('Custom error'))
|
||||
})
|
||||
|
||||
test.serial('/error-midd', async t => {
|
||||
const errorSpy = await interceptError()
|
||||
const err = await t.throws(rp(url('/error-midd')))
|
||||
t.is(err.statusCode, 505)
|
||||
t.true(err.response.body.includes('Middleware Error'))
|
||||
release()
|
||||
// Don't display error since redirect returns a noopApp
|
||||
t.true(errorSpy.notCalled)
|
||||
})
|
||||
|
||||
test.serial('/redirect-middleware', async t => {
|
||||
const errorSpy = await interceptError()
|
||||
await rp(url('/redirect-middleware')) // Should not console.error
|
||||
release()
|
||||
// Don't display error since redirect returns a noopApp
|
||||
t.true(errorSpy.notCalled)
|
||||
})
|
||||
|
||||
test('/redirect-name', async t => {
|
||||
const { html, redirected } = await nuxt.renderRoute('/redirect-name')
|
||||
t.true(html.includes('<div id="__nuxt"></div>'))
|
||||
t.true(redirected.path === '/stateless')
|
||||
t.true(redirected.status === 302)
|
||||
})
|
||||
|
||||
test('/no-ssr', async t => {
|
||||
const { html } = await nuxt.renderRoute('/no-ssr')
|
||||
t.true(
|
||||
html.includes(
|
||||
'<div class="no-ssr-placeholder"><p>Loading...</p></div>'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test('/no-ssr (client-side)', async t => {
|
||||
const window = await nuxt.renderAndGetWindow(url('/no-ssr'))
|
||||
const html = window.document.body.innerHTML
|
||||
t.true(html.includes('Displayed only on client-side</h1>'))
|
||||
})
|
||||
|
||||
test('ETag Header', async t => {
|
||||
const { headers: { etag } } = await rp(url('/stateless'), {
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
// Verify functionality
|
||||
const error = await t.throws(
|
||||
rp(url('/stateless'), { headers: { 'If-None-Match': etag } })
|
||||
)
|
||||
t.is(error.statusCode, 304)
|
||||
})
|
||||
|
||||
test('/_nuxt/server-bundle.json should return 404', async t => {
|
||||
const err = await t.throws(
|
||||
rp(url('/_nuxt/server-bundle.json'), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(err.statusCode, 404)
|
||||
})
|
||||
|
||||
test('/_nuxt/ should return 404', async t => {
|
||||
const err = await t.throws(
|
||||
rp(url('/_nuxt/'), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(err.statusCode, 404)
|
||||
})
|
||||
|
||||
test('/meta', async t => {
|
||||
const { html } = await nuxt.renderRoute('/meta')
|
||||
t.true(html.includes('"meta":[{"works":true}]'))
|
||||
})
|
||||
|
||||
test('/fn-midd', async t => {
|
||||
const err = await t.throws(
|
||||
rp(url('/fn-midd'), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(err.statusCode, 403)
|
||||
t.true(err.response.body.includes('You need to ask the permission'))
|
||||
})
|
||||
|
||||
test('/fn-midd?please=true', async t => {
|
||||
const { html } = await nuxt.renderRoute('/fn-midd?please=true')
|
||||
t.true(html.includes('<h1>Date:'))
|
||||
})
|
||||
|
||||
test('/router-guard', async t => {
|
||||
const { html } = await nuxt.renderRoute('/router-guard')
|
||||
t.true(html.includes('<p>Nuxt.js</p>'))
|
||||
t.false(html.includes('Router Guard'))
|
||||
})
|
||||
|
||||
test('/jsx', async t => {
|
||||
const { html } = await nuxt.renderRoute('/jsx')
|
||||
t.true(html.includes('<h1>JSX Page</h1>'))
|
||||
})
|
||||
|
||||
test('/jsx-link', async t => {
|
||||
const { html } = await nuxt.renderRoute('/jsx-link')
|
||||
t.true(html.includes('<h1>JSX Link Page</h1>'))
|
||||
})
|
||||
|
||||
test('/js-link', async t => {
|
||||
const { html } = await nuxt.renderRoute('/js-link')
|
||||
t.true(html.includes('<h1>vue file is first-class</h1>'))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
@ -1,149 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import { Nuxt, Builder, Utils } from '..'
|
||||
|
||||
import * as browser from './helpers/browser'
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const port = 4014
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let page
|
||||
const dates = {}
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const options = {
|
||||
rootDir: resolve(__dirname, 'fixtures/children'),
|
||||
buildDir: '.nuxt-patch',
|
||||
dev: false,
|
||||
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('Loading /patch and keep ', async t => {
|
||||
page = await browser.page(url('/patch'))
|
||||
|
||||
const h1 = await page.$text('h1')
|
||||
t.true(h1.includes('patch:'))
|
||||
const h2 = await page.$text('h2')
|
||||
t.is(h2, 'Index')
|
||||
dates.patch = await page.$text('[data-date-patch]')
|
||||
})
|
||||
|
||||
test.serial('Navigate to /patch/1', async t => {
|
||||
const { hook } = await page.nuxt.navigate('/patch/1', false)
|
||||
const loading = await page.nuxt.loadingData()
|
||||
t.is(loading.show, true)
|
||||
await hook
|
||||
|
||||
const h2 = await page.$text('h2')
|
||||
t.true(h2.includes('_id:'))
|
||||
dates.id = await page.$text('[data-date-id]')
|
||||
|
||||
t.is(dates.patch, await page.$text('[data-date-patch]'))
|
||||
})
|
||||
|
||||
test.serial('Navigate to /patch/2', async t => {
|
||||
await page.nuxt.navigate('/patch/2')
|
||||
const date = await page.$text('[data-date-id]')
|
||||
|
||||
t.is(await page.$text('h3'), 'Index')
|
||||
t.is(dates.patch, await page.$text('[data-date-patch]'))
|
||||
t.true(+dates.id < +date)
|
||||
dates.id = date
|
||||
})
|
||||
|
||||
test.serial('Navigate to /patch/2?test=true', async t => {
|
||||
await page.nuxt.navigate('/patch/2?test=true')
|
||||
t.is(dates.patch, await page.$text('[data-date-patch]'))
|
||||
t.is(dates.id, await page.$text('[data-date-id]'))
|
||||
})
|
||||
|
||||
test.serial('Navigate to /patch/2#test', async t => {
|
||||
await page.nuxt.navigate('/patch/2#test')
|
||||
t.is(dates.patch, await page.$text('[data-date-patch]'))
|
||||
t.is(dates.id, await page.$text('[data-date-id]'))
|
||||
})
|
||||
|
||||
test.serial('Navigate to /patch/2/child', async t => {
|
||||
await page.nuxt.navigate('/patch/2/child')
|
||||
dates.child = await page.$text('[data-date-child]')
|
||||
dates.slug = await page.$text('[data-date-child-slug]')
|
||||
|
||||
t.is(dates.patch, await page.$text('[data-date-patch]'))
|
||||
t.is(dates.id, await page.$text('[data-date-id]'))
|
||||
t.true(+dates.child > +dates.id)
|
||||
t.true(+dates.slug > +dates.child)
|
||||
})
|
||||
|
||||
test.serial('Navigate to /patch/2/child/1', async t => {
|
||||
await page.nuxt.navigate('/patch/2/child/1')
|
||||
const date = await page.$text('[data-date-child-slug]')
|
||||
|
||||
t.is(dates.patch, await page.$text('[data-date-patch]'))
|
||||
t.is(dates.id, await page.$text('[data-date-id]'))
|
||||
t.is(dates.child, await page.$text('[data-date-child]'))
|
||||
t.true(+date > +dates.slug)
|
||||
dates.slug = date
|
||||
})
|
||||
|
||||
test.serial('Navigate to /patch/2/child/1?foo=bar', async t => {
|
||||
await page.nuxt.navigate('/patch/2/child/1?foo=bar')
|
||||
|
||||
t.is(dates.patch, await page.$text('[data-date-patch]'))
|
||||
t.is(dates.id, await page.$text('[data-date-id]'))
|
||||
t.is(dates.child, await page.$text('[data-date-child]'))
|
||||
t.is(dates.slug, await page.$text('[data-date-child-slug]'))
|
||||
})
|
||||
|
||||
test.serial('Search a country', async t => {
|
||||
const countries = await page.$$text('[data-test-search-result]')
|
||||
t.is(countries.length, 5)
|
||||
|
||||
await page.type('[data-test-search-input]', 'gu')
|
||||
|
||||
await Utils.waitFor(250)
|
||||
const newCountries = await page.$$text('[data-test-search-result]')
|
||||
t.is(newCountries.length, 1)
|
||||
t.deepEqual(newCountries, ['Guinea'])
|
||||
t.deepEqual(await page.nuxt.routeData(), {
|
||||
path: '/patch/2/child/1',
|
||||
query: {
|
||||
foo: 'bar',
|
||||
q: 'gu'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
||||
|
||||
test.after.always('Stop browser', async t => {
|
||||
await page.close()
|
||||
await browser.stop()
|
||||
})
|
@ -1,71 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import { Nuxt, Builder } from '..'
|
||||
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const port = 4013
|
||||
// const url = (route) => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const options = {
|
||||
rootDir: resolve(__dirname, 'fixtures/children'),
|
||||
dev: false,
|
||||
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('/parent', async t => {
|
||||
const { html } = await nuxt.renderRoute('/parent')
|
||||
t.true(html.includes('<h1>I am the parent</h1>'))
|
||||
})
|
||||
|
||||
test('/parent/child', async t => {
|
||||
const { html } = await nuxt.renderRoute('/parent/child')
|
||||
t.true(html.includes('<h1>I am the parent</h1>'))
|
||||
t.true(html.includes('<h2>I am the child</h2>'))
|
||||
})
|
||||
|
||||
test('/parent should call _id.vue', async t => {
|
||||
const { html } = await nuxt.renderRoute('/parent')
|
||||
t.true(html.includes('<h1>I am the parent</h1>'))
|
||||
t.true(html.includes('<h2>Id=</h2>'))
|
||||
})
|
||||
|
||||
test('/parent/1', async t => {
|
||||
const { html } = await nuxt.renderRoute('/parent/1')
|
||||
t.true(html.includes('<h1>I am the parent</h1>'))
|
||||
t.true(html.includes('<h2>Id=1</h2>'))
|
||||
})
|
||||
|
||||
test('/parent/validate-child should display 404', async t => {
|
||||
const { html } = await nuxt.renderRoute('/parent/validate-child')
|
||||
t.true(html.includes('This page could not be found'))
|
||||
})
|
||||
|
||||
test('/parent/validate-child?key=12345', async t => {
|
||||
const { html } = await nuxt.renderRoute('/parent/validate-child?key=12345')
|
||||
t.true(html.includes('<h1>I am the parent</h1>'))
|
||||
t.true(html.includes('<h2>Child valid</h2>'))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
@ -1,96 +0,0 @@
|
||||
import { promisify } from 'util'
|
||||
import test from 'ava'
|
||||
import { resolve } from 'path'
|
||||
import rp from 'request-promise-native'
|
||||
import { exec, spawn } from 'child_process'
|
||||
import { Utils } from '..'
|
||||
|
||||
const execify = promisify(exec)
|
||||
const rootDir = resolve(__dirname, 'fixtures/basic')
|
||||
|
||||
const port = 4011
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
const nuxtBin = resolve(__dirname, '..', 'bin', 'nuxt')
|
||||
|
||||
test.serial('nuxt build', async t => {
|
||||
const { stdout } = await execify(`node ${nuxtBin} build ${rootDir}`)
|
||||
|
||||
t.true(stdout.includes('Compiled successfully'))
|
||||
})
|
||||
|
||||
test.serial('nuxt build -> error config', async t => {
|
||||
const { stderr } = await t.throws(execify(`node ${nuxtBin} build ${rootDir} -c config.js`))
|
||||
t.true(stderr.includes('Could not load config file'))
|
||||
})
|
||||
|
||||
test.serial('nuxt start', async t => {
|
||||
let stdout = ''
|
||||
// let stderr = ''
|
||||
let error
|
||||
let exitCode
|
||||
|
||||
const env = process.env
|
||||
env.PORT = port
|
||||
|
||||
const nuxtStart = spawn('node', [nuxtBin, 'start', rootDir], { env: env })
|
||||
|
||||
nuxtStart.stdout.on('data', data => {
|
||||
stdout += data
|
||||
})
|
||||
|
||||
nuxtStart.stderr.on('data', data => {
|
||||
// stderr += data
|
||||
})
|
||||
|
||||
nuxtStart.on('error', err => {
|
||||
error = err
|
||||
})
|
||||
|
||||
nuxtStart.on('close', code => {
|
||||
exitCode = code
|
||||
})
|
||||
|
||||
// Give the process max 20s to start
|
||||
let iterator = 0
|
||||
while (!stdout.includes('OPEN') && iterator < 80) {
|
||||
await Utils.waitFor(250)
|
||||
iterator++
|
||||
}
|
||||
|
||||
if (iterator === 80) {
|
||||
t.log('WARN: server failed to start successfully in 20 seconds')
|
||||
}
|
||||
|
||||
t.is(error, undefined)
|
||||
t.true(stdout.includes('OPEN'))
|
||||
|
||||
const html = await rp(url('/users/1'))
|
||||
t.true(html.includes('<h1>User: 1</h1>'))
|
||||
|
||||
nuxtStart.kill()
|
||||
|
||||
// Wait max 10s for the process to be killed
|
||||
iterator = 0
|
||||
// eslint-disable-next-line no-unmodified-loop-condition
|
||||
while (exitCode === undefined && iterator < 40) {
|
||||
await Utils.waitFor(250)
|
||||
iterator++
|
||||
}
|
||||
|
||||
if (iterator >= 40) {
|
||||
t.log(
|
||||
`WARN: we were unable to automatically kill the child process with pid: ${
|
||||
nuxtStart.pid
|
||||
}`
|
||||
)
|
||||
}
|
||||
|
||||
t.is(exitCode, null)
|
||||
})
|
||||
|
||||
test.serial('nuxt generate', async t => {
|
||||
const { stdout } = await execify(`node ${nuxtBin} generate ${rootDir}`)
|
||||
|
||||
t.true(stdout.includes('vue-ssr-client-manifest.json'))
|
||||
})
|
@ -1,59 +0,0 @@
|
||||
import test from 'ava'
|
||||
import rp from 'request-promise-native'
|
||||
import { Nuxt, Builder } from '..'
|
||||
import { interceptLog } from './helpers/console'
|
||||
import { loadConfig } from './helpers/config'
|
||||
|
||||
const port = 4007
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let builder = null
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.before('Init Nuxt.js', async t => {
|
||||
const config = loadConfig('/custom-dirs', { dev: false })
|
||||
|
||||
const logSpy = await interceptLog(async () => {
|
||||
nuxt = new Nuxt(config)
|
||||
builder = new Builder(nuxt)
|
||||
await builder.build()
|
||||
await nuxt.listen(4007, 'localhost')
|
||||
})
|
||||
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
t.true(logSpy.calledWithMatch('OPEN'))
|
||||
})
|
||||
|
||||
test('custom assets directory', async t => {
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('.global-css-selector'))
|
||||
})
|
||||
|
||||
test('custom layouts directory', async t => {
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('<p>I have custom layouts directory</p>'))
|
||||
})
|
||||
|
||||
test('custom middleware directory', async t => {
|
||||
const window = await nuxt.renderAndGetWindow(url('/user-agent'))
|
||||
const html = window.document.body.innerHTML
|
||||
t.true(html.includes('<pre>Mozilla'))
|
||||
})
|
||||
|
||||
test('custom pages directory', async t => {
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('<h1>I have custom pages directory</h1>'))
|
||||
})
|
||||
|
||||
test('custom static directory', async t => {
|
||||
const { headers } = await rp(url('/test.txt'), {
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
t.is(headers['cache-control'], 'public, max-age=0')
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
@ -1,102 +0,0 @@
|
||||
import test from 'ava'
|
||||
import rp from 'request-promise-native'
|
||||
import { Nuxt, Builder } from '..'
|
||||
import { interceptLog, interceptError, release } from './helpers/console'
|
||||
import { loadConfig } from './helpers/config'
|
||||
|
||||
const port = 4009
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.before('Init Nuxt.js', async t => {
|
||||
const config = loadConfig('debug')
|
||||
|
||||
const logSpy = await interceptLog(async () => {
|
||||
nuxt = new Nuxt(config)
|
||||
await new Builder(nuxt).build()
|
||||
await nuxt.listen(port, 'localhost')
|
||||
})
|
||||
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
t.true(logSpy.calledWithMatch('OPEN'))
|
||||
})
|
||||
|
||||
test.serial('/test/__open-in-editor (open-in-editor)', async t => {
|
||||
const { body } = await rp(
|
||||
url('/test/__open-in-editor?file=pages/index.vue'),
|
||||
{ resolveWithFullResponse: true }
|
||||
)
|
||||
t.is(body, '')
|
||||
})
|
||||
|
||||
test.serial(
|
||||
'/test/__open-in-editor should return error (open-in-editor)',
|
||||
async t => {
|
||||
const { error, statusCode } = await t.throws(
|
||||
rp(url('/test/__open-in-editor?file='), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(statusCode, 500)
|
||||
t.is(
|
||||
error,
|
||||
'launch-editor-middleware: required query param "file" is missing.'
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test.serial('/test/error should return error stack trace (Youch)', async t => {
|
||||
const errorSpy = await interceptError()
|
||||
const { response, error } = await t.throws(
|
||||
nuxt.renderAndGetWindow(url('/test/error'))
|
||||
)
|
||||
t.is(response.statusCode, 500)
|
||||
t.is(response.statusMessage, 'NuxtServerError')
|
||||
t.true(error.includes('test youch !'))
|
||||
t.true(error.includes('<div class="error-frames">'))
|
||||
release()
|
||||
t.true(errorSpy.calledTwice)
|
||||
t.true(errorSpy.getCall(0).args[0].includes('test youch !'))
|
||||
t.true(errorSpy.getCall(1).args[0].message.includes('test youch !'))
|
||||
})
|
||||
|
||||
test.serial('/test/error no source-map (Youch)', async t => {
|
||||
const sourceMaps = nuxt.renderer.resources.serverBundle.maps
|
||||
nuxt.renderer.resources.serverBundle.maps = {}
|
||||
|
||||
const errorSpy = await interceptError()
|
||||
const { response, error } = await t.throws(
|
||||
nuxt.renderAndGetWindow(url('/test/error'))
|
||||
)
|
||||
t.is(response.statusCode, 500)
|
||||
t.is(response.statusMessage, 'NuxtServerError')
|
||||
t.true(error.includes('test youch !'))
|
||||
t.true(error.includes('<div class="error-frames">'))
|
||||
release()
|
||||
t.true(errorSpy.calledTwice)
|
||||
t.true(errorSpy.getCall(0).args[0].includes('test youch !'))
|
||||
t.true(errorSpy.getCall(1).args[0].message.includes('test youch !'))
|
||||
|
||||
nuxt.renderer.resources.serverBundle.maps = sourceMaps
|
||||
})
|
||||
|
||||
test.serial('/test/error should return json format error (Youch)', async t => {
|
||||
const opts = {
|
||||
headers: {
|
||||
accept: 'application/json'
|
||||
},
|
||||
resolveWithFullResponse: true
|
||||
}
|
||||
const errorSpy = await interceptError()
|
||||
const { response: { headers } } = await t.throws(rp(url('/test/error'), opts))
|
||||
t.is(headers['content-type'], 'text/json; charset=utf-8')
|
||||
release()
|
||||
t.true(errorSpy.calledTwice)
|
||||
t.true(errorSpy.getCall(0).args[0].includes('test youch !'))
|
||||
t.true(errorSpy.getCall(1).args[0].message.includes('test youch !'))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
@ -1,34 +0,0 @@
|
||||
import test from 'ava'
|
||||
import { Nuxt, Builder } from '..'
|
||||
import { intercept } from './helpers/console'
|
||||
import { loadConfig } from './helpers/config'
|
||||
|
||||
const port = 4010
|
||||
|
||||
let nuxt = null
|
||||
let builder = null
|
||||
let buildSpies = null
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const config = loadConfig('deprecate', { dev: false })
|
||||
|
||||
buildSpies = await intercept(async () => {
|
||||
nuxt = new Nuxt(config)
|
||||
builder = await new Builder(nuxt)
|
||||
await builder.build()
|
||||
await nuxt.listen(port, 'localhost')
|
||||
})
|
||||
|
||||
t.true(buildSpies.log.calledWithMatch('DONE'))
|
||||
t.true(buildSpies.log.calledWithMatch('OPEN'))
|
||||
})
|
||||
|
||||
test.serial('Deprecated: module.addVendor()', async t => {
|
||||
t.true(buildSpies.warn.calledWithMatch('module: addVendor is no longer necessary'))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
@ -1,122 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
import fs from 'fs'
|
||||
import { promisify } from 'util'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import { Nuxt, Builder } from '..'
|
||||
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const readFile = promisify(fs.readFile)
|
||||
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const config = {
|
||||
rootDir: resolve(__dirname, 'fixtures/dynamic-routes'),
|
||||
dev: false,
|
||||
build: {
|
||||
stats: false
|
||||
}
|
||||
}
|
||||
|
||||
const logSpy = await interceptLog(async () => {
|
||||
const nuxt = new Nuxt(config)
|
||||
await new Builder(nuxt).build()
|
||||
})
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
})
|
||||
|
||||
test('Check .nuxt/router.js', t => {
|
||||
return readFile(
|
||||
resolve(__dirname, './fixtures/dynamic-routes/.nuxt/router.js'),
|
||||
'utf-8'
|
||||
).then(routerFile => {
|
||||
routerFile = routerFile
|
||||
.slice(routerFile.indexOf('routes: ['))
|
||||
.replace('routes: [', '[')
|
||||
.replace(/ _[0-9A-z]+,/g, ' "",')
|
||||
routerFile = routerFile.substr(
|
||||
routerFile.indexOf('['),
|
||||
routerFile.lastIndexOf(']') + 1
|
||||
)
|
||||
let routes = eval('( ' + routerFile + ')') // eslint-disable-line no-eval
|
||||
// pages/test/index.vue
|
||||
t.is(routes[0].path, '/test')
|
||||
t.is(routes[0].name, 'test')
|
||||
// pages/posts.vue
|
||||
t.is(routes[1].path, '/posts')
|
||||
t.is(routes[1].name, 'posts')
|
||||
t.is(routes[1].children.length, 1)
|
||||
// pages/posts/_id.vue
|
||||
t.is(routes[1].children[0].path, ':id?')
|
||||
t.is(routes[1].children[0].name, 'posts-id')
|
||||
// pages/parent.vue
|
||||
t.is(routes[2].path, '/parent')
|
||||
t.falsy(routes[2].name) // parent route has no name
|
||||
// pages/parent/*.vue
|
||||
t.is(routes[2].children.length, 3) // parent has 3 children
|
||||
t.deepEqual(routes[2].children.map(r => r.path), ['', 'teub', 'child'])
|
||||
t.deepEqual(routes[2].children.map(r => r.name), [
|
||||
'parent',
|
||||
'parent-teub',
|
||||
'parent-child'
|
||||
])
|
||||
// pages/test/projects/index.vue
|
||||
t.is(routes[3].path, '/test/projects')
|
||||
t.is(routes[3].name, 'test-projects')
|
||||
// pages/test/users.vue
|
||||
t.is(routes[4].path, '/test/users')
|
||||
t.falsy(routes[4].name) // parent route has no name
|
||||
// pages/test/users/*.vue
|
||||
t.is(routes[4].children.length, 5) // parent has 5 children
|
||||
t.deepEqual(routes[4].children.map(r => r.path), [
|
||||
'',
|
||||
'projects',
|
||||
'projects/:category',
|
||||
':id',
|
||||
':index/teub'
|
||||
])
|
||||
t.deepEqual(routes[4].children.map(r => r.name), [
|
||||
'test-users',
|
||||
'test-users-projects',
|
||||
'test-users-projects-category',
|
||||
'test-users-id',
|
||||
'test-users-index-teub'
|
||||
])
|
||||
// pages/test/songs/toto.vue
|
||||
t.is(routes[5].path, '/test/songs/toto')
|
||||
t.is(routes[5].name, 'test-songs-toto')
|
||||
// pages/test/projects/_category.vue
|
||||
t.is(routes[6].path, '/test/projects/:category')
|
||||
t.is(routes[6].name, 'test-projects-category')
|
||||
// pages/test/songs/_id.vue
|
||||
t.is(routes[7].path, '/test/songs/:id?')
|
||||
t.is(routes[7].name, 'test-songs-id')
|
||||
// pages/users/_id.vue
|
||||
t.is(routes[8].path, '/users/:id?')
|
||||
t.is(routes[8].name, 'users-id')
|
||||
// pages/test/_.vue
|
||||
t.is(routes[9].path, '/test/*')
|
||||
t.is(routes[9].name, 'test-all')
|
||||
|
||||
// pages/index.vue
|
||||
t.is(routes[10].path, '/')
|
||||
t.is(routes[10].name, 'index')
|
||||
|
||||
// pages/_slug.vue
|
||||
t.is(routes[11].path, '/:slug')
|
||||
t.is(routes[11].name, 'slug')
|
||||
// pages/_key/_id.vue
|
||||
t.is(routes[12].path, '/:key/:id?')
|
||||
t.is(routes[12].name, 'key-id')
|
||||
// pages/_.vue
|
||||
t.is(routes[13].path, '/*/p/*')
|
||||
t.is(routes[13].name, 'all-p-all')
|
||||
// pages/_/_.vue
|
||||
t.is(routes[14].path, '/*/*')
|
||||
t.is(routes[14].name, 'all-all')
|
||||
// pages/_.vue
|
||||
t.is(routes[15].path, '/*')
|
||||
t.is(routes[15].name, 'all')
|
||||
})
|
||||
})
|
203
test/e2e/basic.browser.test.js
Normal file
203
test/e2e/basic.browser.test.js
Normal file
@ -0,0 +1,203 @@
|
||||
import { Nuxt } from '../..'
|
||||
import Browser from '../utils/browser'
|
||||
import { loadFixture, getPort } from '../utils'
|
||||
|
||||
let port
|
||||
const browser = new Browser()
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let page = null
|
||||
|
||||
describe('basic browser', () => {
|
||||
beforeAll(async () => {
|
||||
const config = loadFixture('basic')
|
||||
nuxt = new Nuxt(config)
|
||||
port = await getPort()
|
||||
await nuxt.listen(port, 'localhost')
|
||||
|
||||
await browser.start({
|
||||
// slowMo: 50,
|
||||
// headless: false
|
||||
})
|
||||
})
|
||||
|
||||
test('Open /', async () => {
|
||||
page = await browser.page(url('/'))
|
||||
|
||||
expect(await page.$text('h1')).toBe('Index page')
|
||||
})
|
||||
|
||||
test('/stateless', async () => {
|
||||
const { hook } = await page.nuxt.navigate('/stateless', false)
|
||||
const loading = await page.nuxt.loadingData()
|
||||
|
||||
expect(loading.show).toBe(true)
|
||||
await hook
|
||||
expect(await page.$text('h1')).toBe('My component!')
|
||||
})
|
||||
|
||||
test('/css', async () => {
|
||||
await page.nuxt.navigate('/css')
|
||||
|
||||
expect(await page.$text('.red')).toBe('This is red')
|
||||
expect(await page.$eval('.red', red => window.getComputedStyle(red).color)).toBe('rgb(255, 0, 0)')
|
||||
})
|
||||
|
||||
test.skip('/stateful', async () => {
|
||||
const { hook } = await page.nuxt.navigate('/stateful')
|
||||
|
||||
await hook
|
||||
expect(await page.$text('p')).toBe('The answer is 42')
|
||||
})
|
||||
|
||||
test('/store', async () => {
|
||||
await page.nuxt.navigate('/store')
|
||||
|
||||
expect(await page.$text('h1')).toBe('Vuex Nested Modules')
|
||||
expect(await page.$text('p')).toBe('1')
|
||||
})
|
||||
|
||||
test('/head', async () => {
|
||||
const msg = new Promise(resolve =>
|
||||
page.on('console', msg => resolve(msg.text()))
|
||||
)
|
||||
await page.nuxt.navigate('/head')
|
||||
const metas = await page.$$attr('meta', 'content')
|
||||
|
||||
expect(await msg).toBe('Body script!')
|
||||
expect(await page.title()).toBe('My title - Nuxt.js')
|
||||
expect(await page.$text('h1')).toBe('I can haz meta tags')
|
||||
expect(metas[0]).toBe('my meta')
|
||||
})
|
||||
|
||||
test('/async-data', async () => {
|
||||
await page.nuxt.navigate('/async-data')
|
||||
|
||||
expect(await page.$text('p')).toBe('Nuxt.js')
|
||||
})
|
||||
|
||||
test('/await-async-data', async () => {
|
||||
await page.nuxt.navigate('/await-async-data')
|
||||
|
||||
expect(await page.$text('p')).toBe('Await Nuxt.js')
|
||||
})
|
||||
|
||||
test('/callback-async-data', async () => {
|
||||
await page.nuxt.navigate('/callback-async-data')
|
||||
|
||||
expect(await page.$text('p')).toBe('Callback Nuxt.js')
|
||||
})
|
||||
|
||||
test('/users/1', async () => {
|
||||
await page.nuxt.navigate('/users/1')
|
||||
|
||||
expect(await page.$text('h1')).toBe('User: 1')
|
||||
})
|
||||
|
||||
test('/validate should display a 404', async () => {
|
||||
await page.nuxt.navigate('/validate')
|
||||
|
||||
const error = await page.nuxt.errorData()
|
||||
|
||||
expect(error.statusCode).toBe(404)
|
||||
expect(error.message).toBe('This page could not be found')
|
||||
})
|
||||
|
||||
test('/validate?valid=true', async () => {
|
||||
await page.nuxt.navigate('/validate?valid=true')
|
||||
|
||||
expect(await page.$text('h1')).toBe('I am valid')
|
||||
})
|
||||
|
||||
test('/redirect', async () => {
|
||||
await page.nuxt.navigate('/redirect')
|
||||
|
||||
expect(await page.$text('h1')).toBe('Index page')
|
||||
})
|
||||
|
||||
test('/error', async () => {
|
||||
await page.nuxt.navigate('/error')
|
||||
|
||||
expect(await page.nuxt.errorData()).toEqual({ statusCode: 500 })
|
||||
expect(await page.$text('.title')).toBe('Error mouahahah')
|
||||
})
|
||||
|
||||
test('/error2', async () => {
|
||||
await page.nuxt.navigate('/error2')
|
||||
|
||||
expect(await page.$text('.title')).toBe('Custom error')
|
||||
expect(await page.nuxt.errorData()).toEqual({ message: 'Custom error' })
|
||||
})
|
||||
|
||||
test('/redirect-middleware', async () => {
|
||||
await page.nuxt.navigate('/redirect-middleware')
|
||||
|
||||
expect(await page.$text('h1')).toBe('Index page')
|
||||
})
|
||||
|
||||
test('/redirect-external', async () => {
|
||||
// New page for redirecting to external link.
|
||||
const page = await browser.page(url('/'))
|
||||
|
||||
await page.nuxt.navigate('/redirect-external', false)
|
||||
|
||||
await page.waitForFunction(
|
||||
() => window.location.href === 'https://nuxtjs.org/'
|
||||
)
|
||||
page.close()
|
||||
})
|
||||
|
||||
test('/redirect-name', async () => {
|
||||
await page.nuxt.navigate('/redirect-name')
|
||||
|
||||
expect(await page.$text('h1')).toBe('My component!')
|
||||
})
|
||||
|
||||
test('/no-ssr', async () => {
|
||||
await page.nuxt.navigate('/no-ssr')
|
||||
|
||||
expect(await page.$text('h1')).toBe('Displayed only on client-side')
|
||||
})
|
||||
|
||||
test('/meta', async () => {
|
||||
await page.nuxt.navigate('/meta')
|
||||
|
||||
const state = await page.nuxt.storeState()
|
||||
expect(state.meta).toEqual([{ works: true }])
|
||||
})
|
||||
|
||||
test('/fn-midd', async () => {
|
||||
await page.nuxt.navigate('/fn-midd')
|
||||
|
||||
expect(await page.$text('.title')).toBe('You need to ask the permission')
|
||||
expect(await page.nuxt.errorData()).toEqual({
|
||||
message: 'You need to ask the permission',
|
||||
statusCode: 403
|
||||
})
|
||||
})
|
||||
|
||||
test('/fn-midd?please=true', async () => {
|
||||
await page.nuxt.navigate('/fn-midd?please=true')
|
||||
|
||||
const h1 = await page.$text('h1')
|
||||
expect(h1.includes('Date:')).toBe(true)
|
||||
})
|
||||
|
||||
test('/router-guard', async () => {
|
||||
await page.nuxt.navigate('/router-guard')
|
||||
|
||||
const p = await page.$text('p')
|
||||
expect(p).toBe('Nuxt.js')
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test('Closing server and nuxt.js', async () => {
|
||||
await nuxt.close()
|
||||
})
|
||||
|
||||
test('Stop browser', async () => {
|
||||
await page.close()
|
||||
await browser.close()
|
||||
})
|
||||
})
|
133
test/e2e/children.patch.browser.test.js
Normal file
133
test/e2e/children.patch.browser.test.js
Normal file
@ -0,0 +1,133 @@
|
||||
import { Nuxt, Utils } from '../..'
|
||||
import Browser from '../utils/browser'
|
||||
import { loadFixture, getPort } from '../utils'
|
||||
|
||||
let port
|
||||
const browser = new Browser()
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let page
|
||||
const dates = {}
|
||||
|
||||
describe('children patch (browser)', () => {
|
||||
beforeAll(async () => {
|
||||
const options = loadFixture('children')
|
||||
nuxt = new Nuxt(options)
|
||||
port = await getPort()
|
||||
await nuxt.listen(port, 'localhost')
|
||||
})
|
||||
|
||||
test('Start browser', async () => {
|
||||
expect.assertions(0) // suppress 'no assertions' warning
|
||||
await browser.start({
|
||||
// slowMo: 50,
|
||||
// headless: false
|
||||
})
|
||||
})
|
||||
|
||||
test('Loading /patch and keep ', async () => {
|
||||
page = await browser.page(url('/patch'))
|
||||
|
||||
const h1 = await page.$text('h1')
|
||||
expect(h1.includes('patch:')).toBe(true)
|
||||
const h2 = await page.$text('h2')
|
||||
expect(h2).toBe('Index')
|
||||
dates.patch = await page.$text('[data-date-patch]')
|
||||
})
|
||||
|
||||
test('Navigate to /patch/1', async () => {
|
||||
const { hook } = await page.nuxt.navigate('/patch/1', false)
|
||||
const loading = await page.nuxt.loadingData()
|
||||
expect(loading.show).toBe(true)
|
||||
await hook
|
||||
|
||||
const h2 = await page.$text('h2')
|
||||
expect(h2.includes('_id:')).toBe(true)
|
||||
dates.id = await page.$text('[data-date-id]')
|
||||
|
||||
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
|
||||
})
|
||||
|
||||
test('Navigate to /patch/2', async () => {
|
||||
await page.nuxt.navigate('/patch/2')
|
||||
const date = await page.$text('[data-date-id]')
|
||||
|
||||
expect(await page.$text('h3')).toBe('Index')
|
||||
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
|
||||
expect(+dates.id < +date).toBe(true)
|
||||
dates.id = date
|
||||
})
|
||||
|
||||
test('Navigate to /patch/2?test=true', async () => {
|
||||
await page.nuxt.navigate('/patch/2?test=true')
|
||||
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
|
||||
expect(dates.id).toBe(await page.$text('[data-date-id]'))
|
||||
})
|
||||
|
||||
test('Navigate to /patch/2#test', async () => {
|
||||
await page.nuxt.navigate('/patch/2#test')
|
||||
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
|
||||
expect(dates.id).toBe(await page.$text('[data-date-id]'))
|
||||
})
|
||||
|
||||
test('Navigate to /patch/2/child', async () => {
|
||||
await page.nuxt.navigate('/patch/2/child')
|
||||
dates.child = await page.$text('[data-date-child]')
|
||||
dates.slug = await page.$text('[data-date-child-slug]')
|
||||
|
||||
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
|
||||
expect(dates.id).toBe(await page.$text('[data-date-id]'))
|
||||
expect(+dates.child > +dates.id).toBe(true)
|
||||
expect(+dates.slug > +dates.child).toBe(true)
|
||||
})
|
||||
|
||||
test('Navigate to /patch/2/child/1', async () => {
|
||||
await page.nuxt.navigate('/patch/2/child/1')
|
||||
const date = await page.$text('[data-date-child-slug]')
|
||||
|
||||
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
|
||||
expect(dates.id).toBe(await page.$text('[data-date-id]'))
|
||||
expect(dates.child).toBe(await page.$text('[data-date-child]'))
|
||||
expect(+date > +dates.slug).toBe(true)
|
||||
dates.slug = date
|
||||
})
|
||||
|
||||
test('Navigate to /patch/2/child/1?foo=bar', async () => {
|
||||
await page.nuxt.navigate('/patch/2/child/1?foo=bar')
|
||||
|
||||
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
|
||||
expect(dates.id).toBe(await page.$text('[data-date-id]'))
|
||||
expect(dates.child).toBe(await page.$text('[data-date-child]'))
|
||||
expect(dates.slug).toBe(await page.$text('[data-date-child-slug]'))
|
||||
})
|
||||
|
||||
test('Search a country', async () => {
|
||||
const countries = await page.$$text('[data-test-search-result]')
|
||||
expect(countries.length).toBe(5)
|
||||
|
||||
await page.type('[data-test-search-input]', 'gu')
|
||||
|
||||
await Utils.waitFor(250)
|
||||
const newCountries = await page.$$text('[data-test-search-result]')
|
||||
expect(newCountries.length).toBe(1)
|
||||
expect(newCountries).toEqual(['Guinea'])
|
||||
expect(await page.nuxt.routeData()).toEqual({
|
||||
path: '/patch/2/child/1',
|
||||
query: {
|
||||
foo: 'bar',
|
||||
q: 'gu'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test('Closing server and nuxt.js', async () => {
|
||||
await nuxt.close()
|
||||
})
|
||||
|
||||
test('Stop browser', async () => {
|
||||
await page.close()
|
||||
await browser.close()
|
||||
})
|
||||
})
|
@ -1,89 +0,0 @@
|
||||
import test from 'ava'
|
||||
import rp from 'request-promise-native'
|
||||
import { Nuxt, Builder } from '..'
|
||||
import { interceptLog, interceptError, release } from './helpers/console'
|
||||
import { loadConfig } from './helpers/config'
|
||||
|
||||
const port = 4005
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let logSpy
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const config = loadConfig('error', { dev: false })
|
||||
|
||||
logSpy = await interceptLog(async () => {
|
||||
nuxt = new Nuxt(config)
|
||||
await new Builder(nuxt).build()
|
||||
await nuxt.listen(port, 'localhost')
|
||||
})
|
||||
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
t.true(logSpy.calledWithMatch('OPEN'))
|
||||
})
|
||||
|
||||
test.serial('/ should display an error', async t => {
|
||||
const error = await t.throws(nuxt.renderRoute('/'))
|
||||
t.true(error.message.includes('not_defined is not defined'))
|
||||
})
|
||||
|
||||
test.serial('/404 should display an error too', async t => {
|
||||
let { error } = await nuxt.renderRoute('/404')
|
||||
t.true(error.message.includes('This page could not be found'))
|
||||
})
|
||||
|
||||
test.serial('/ with renderAndGetWindow()', async t => {
|
||||
const errorSpy = await interceptError()
|
||||
const err = await t.throws(nuxt.renderAndGetWindow(url('/')))
|
||||
t.is(err.response.statusCode, 500)
|
||||
t.is(err.response.statusMessage, 'NuxtServerError')
|
||||
release()
|
||||
t.true(errorSpy.calledOnce)
|
||||
t.true(
|
||||
errorSpy
|
||||
.getCall(0)
|
||||
.args[0].message.includes(
|
||||
'render function or template not defined in component: anonymous'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test.serial('/ with text/json content', async t => {
|
||||
const opts = {
|
||||
headers: {
|
||||
accept: 'application/json'
|
||||
},
|
||||
resolveWithFullResponse: true
|
||||
}
|
||||
const errorSpy = await interceptError()
|
||||
const { response: { headers } } = await t.throws(rp(url('/'), opts))
|
||||
t.is(headers['content-type'], 'text/json; charset=utf-8')
|
||||
release()
|
||||
t.true(errorSpy.calledOnce)
|
||||
t.true(
|
||||
errorSpy
|
||||
.getCall(0)
|
||||
.args[0].message.includes(
|
||||
'render function or template not defined in component: anonymous'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test.serial('Deprecated: dev in build.extend()', async t => {
|
||||
t.true(logSpy.calledWith('[build:done]: hook error'))
|
||||
})
|
||||
|
||||
test.serial('Error: resolvePath()', async t => {
|
||||
let error = t.throws(() => nuxt.resolvePath())
|
||||
t.true(error instanceof TypeError)
|
||||
|
||||
error = t.throws(() => nuxt.resolvePath('@/pages/about.vue'))
|
||||
t.true(error.message.includes('Cannot resolve "@/pages/about.vue"'))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
@ -1,47 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
import test from 'ava'
|
||||
import express from 'express'
|
||||
import rp from 'request-promise-native'
|
||||
|
||||
import { Nuxt, Builder } from '..'
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const port = 4000
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt
|
||||
let app
|
||||
|
||||
// Init nuxt.js and create express server
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const config = {
|
||||
rootDir: resolve(__dirname, 'fixtures/basic'),
|
||||
buildDir: '.nuxt-express',
|
||||
dev: false,
|
||||
build: {
|
||||
stats: false
|
||||
}
|
||||
}
|
||||
|
||||
const logSpy = await interceptLog(async () => {
|
||||
nuxt = new Nuxt(config)
|
||||
await new Builder(nuxt).build()
|
||||
})
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
|
||||
// Create express app
|
||||
app = express()
|
||||
|
||||
// Register nuxt
|
||||
app.use(nuxt.render)
|
||||
|
||||
// Start listening on localhost:4000
|
||||
app.listen(port)
|
||||
})
|
||||
|
||||
test('/stateless with express', async t => {
|
||||
const html = await rp(url('/stateless'))
|
||||
|
||||
t.true(html.includes('<h1>My component!</h1>'))
|
||||
})
|
@ -1,116 +0,0 @@
|
||||
import http from 'http'
|
||||
import { existsSync } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
|
||||
import test from 'ava'
|
||||
import serveStatic from 'serve-static'
|
||||
import finalhandler from 'finalhandler'
|
||||
import rp from 'request-promise-native'
|
||||
|
||||
import { Nuxt, Builder, Generator, Options } from '..'
|
||||
|
||||
import { intercept, interceptLog } from './helpers/console'
|
||||
import { loadConfig } from './helpers/config'
|
||||
|
||||
const port = 4015
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let server = null
|
||||
let generator = null
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4015
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
let config = loadConfig('basic', {
|
||||
buildDir: '.nuxt-spa-fallback',
|
||||
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('default creates /200.html as fallback', async t => {
|
||||
const html = await rp(url('/200.html'))
|
||||
t.false(html.includes('<h1>Index page</h1>'))
|
||||
t.false(html.includes('data-server-rendered'))
|
||||
t.true(existsSync(resolve(__dirname, 'fixtures/basic/dist', '200.html')))
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', '404.html')))
|
||||
})
|
||||
|
||||
test.serial('nuxt re-generating with generate.fallback = false', async t => {
|
||||
const logSpy = await interceptLog(async () => {
|
||||
nuxt.options.generate.fallback = false
|
||||
await generator.generate()
|
||||
})
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
})
|
||||
|
||||
test.serial('false creates no fallback', async t => {
|
||||
const error = await t.throws(rp(url('/200.html')))
|
||||
t.true(error.statusCode === 404)
|
||||
t.true(error.response.body.includes('Cannot GET /200.html'))
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', '200.html')))
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', '404.html')))
|
||||
})
|
||||
|
||||
test.serial('generate.fallback = true is transformed to /404.html', async t => {
|
||||
nuxt.options.generate.fallback = true
|
||||
const options = Options.from(nuxt.options)
|
||||
t.is(options.generate.fallback, '404.html')
|
||||
})
|
||||
|
||||
test.serial('nuxt re-generating with generate.fallback = "spa-fallback.html"', async t => {
|
||||
const logSpy = await interceptLog(async () => {
|
||||
nuxt.options.generate.fallback = 'spa-fallback.html'
|
||||
await generator.generate()
|
||||
})
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
})
|
||||
|
||||
test.serial('"spa-fallback.html" creates /spa-fallback.html as fallback', async t => {
|
||||
const html = await rp(url('/spa-fallback.html'))
|
||||
t.false(html.includes('<h1>Index page</h1>'))
|
||||
t.false(html.includes('data-server-rendered'))
|
||||
t.true(
|
||||
existsSync(resolve(__dirname, 'fixtures/basic/dist', 'spa-fallback.html'))
|
||||
)
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', '404.html')))
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', '200.html')))
|
||||
})
|
||||
|
||||
test.serial('nuxt re-generating with generate.fallback = "index.html"', async t => {
|
||||
const {log: logSpy, warn: warnSpy} = await intercept({warn: true, log: true}, async () => {
|
||||
nuxt.options.generate.fallback = 'index.html'
|
||||
await generator.generate()
|
||||
})
|
||||
t.true(warnSpy.calledWithMatch('WARN')) // Must emit warnning
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
})
|
||||
|
||||
test.serial('"index.html" creates /index.html as fallback', async t => {
|
||||
const html = await rp(url('/index.html'))
|
||||
t.true(html.includes('<h1>Index page</h1>'))
|
||||
t.true(html.includes('data-server-rendered'))
|
||||
t.true(existsSync(resolve(__dirname, 'fixtures/basic/dist', 'index.html')))
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', '404.html')))
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', '200.html')))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server', async t => {
|
||||
await server.close()
|
||||
})
|
14
test/fixtures/basic/nuxt.config.js
vendored
14
test/fixtures/basic/nuxt.config.js
vendored
@ -3,6 +3,15 @@ import path from 'path'
|
||||
export default {
|
||||
generate: {
|
||||
routes: [
|
||||
// TODO: generate with {build: false} does not scans pages!
|
||||
'/stateless',
|
||||
'/css',
|
||||
'/stateful',
|
||||
'/head',
|
||||
'/async-data',
|
||||
'/validate',
|
||||
'/redirect',
|
||||
|
||||
'/users/1',
|
||||
'/users/2',
|
||||
{ route: '/users/3', payload: { id: 3000 } }
|
||||
@ -10,6 +19,11 @@ export default {
|
||||
interval: 200,
|
||||
subFolders: true
|
||||
},
|
||||
head: {
|
||||
titleTemplate: (titleChunk) => {
|
||||
return titleChunk ? `${titleChunk} - Nuxt.js` : 'Nuxt.js'
|
||||
}
|
||||
},
|
||||
modulesDir: path.join(__dirname, '..', '..', '..', 'node_modules'),
|
||||
hooks: {
|
||||
ready(nuxt) {
|
||||
|
8
test/fixtures/error/nuxt.config.js
vendored
8
test/fixtures/error/nuxt.config.js
vendored
@ -1,12 +1,4 @@
|
||||
export default {
|
||||
hooks(hook) {
|
||||
hook('build:done', nuxt => {
|
||||
throw new Error('hook error')
|
||||
})
|
||||
hook('error', ({message}, from) => {
|
||||
console.log(`[${from}]: ${message}`) // eslint-disable-line no-console
|
||||
})
|
||||
},
|
||||
build: {
|
||||
stats: false
|
||||
}
|
||||
|
4
test/fixtures/module/modules/hooks/index.js
vendored
4
test/fixtures/module/modules/hooks/index.js
vendored
@ -19,8 +19,4 @@ export default function () {
|
||||
this.nuxt.hook('build:done', (builder) => {
|
||||
this.nuxt.__builder_plugin = builder && ctr++
|
||||
})
|
||||
|
||||
this.nuxt.hook('build:extendRoutes', (builder) => {
|
||||
throw new Error('hook error testing')
|
||||
})
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
import test from 'ava'
|
||||
import { Nuxt, Generator } from '..'
|
||||
|
||||
test('initRoutes with routes (fn => array)', async t => {
|
||||
const array = ['/1', '/2', '/3', '/4']
|
||||
const config = {
|
||||
generate: {
|
||||
routes: array
|
||||
}
|
||||
}
|
||||
const nuxt = new Nuxt(config)
|
||||
const generator = new Generator(nuxt)
|
||||
const routes = await generator.initRoutes()
|
||||
|
||||
t.is(routes.length, array.length)
|
||||
routes.map((route, index) => {
|
||||
t.is(route.route, array[index])
|
||||
})
|
||||
})
|
||||
|
||||
test('initRoutes with routes (fn())', async t => {
|
||||
const array = ['/1', '/2', '/3', '/4']
|
||||
const config = {
|
||||
generate: {
|
||||
routes() {
|
||||
return array
|
||||
}
|
||||
}
|
||||
}
|
||||
const nuxt = new Nuxt(config)
|
||||
const generator = new Generator(nuxt)
|
||||
const routes = await generator.initRoutes()
|
||||
|
||||
t.is(routes.length, array.length)
|
||||
routes.map((route, index) => {
|
||||
t.is(route.route, array[index])
|
||||
})
|
||||
})
|
||||
|
||||
test('initRoutes with routes (fn(args))', async t => {
|
||||
const config = {
|
||||
generate: {
|
||||
routes(array) {
|
||||
return array
|
||||
}
|
||||
}
|
||||
}
|
||||
const nuxt = new Nuxt(config)
|
||||
const generator = new Generator(nuxt)
|
||||
const array = ['/1', '/2', '/3', '/4']
|
||||
const routes = await generator.initRoutes(array)
|
||||
|
||||
t.is(routes.length, array.length)
|
||||
routes.map((route, index) => {
|
||||
t.is(route.route, array[index])
|
||||
})
|
||||
})
|
||||
|
||||
test('initRoutes with routes (fn(cb, args))', async t => {
|
||||
const config = {
|
||||
generate: {
|
||||
routes(cb, arg1, arg2, arg3, arg4) {
|
||||
cb(null, [arg1, arg2, arg3, arg4])
|
||||
}
|
||||
}
|
||||
}
|
||||
const nuxt = new Nuxt(config)
|
||||
const generator = new Generator(nuxt)
|
||||
const array = ['/1', '/2', '/3', '/4']
|
||||
const routes = await generator.initRoutes(...array)
|
||||
|
||||
t.is(routes.length, array.length)
|
||||
routes.map((route, index) => {
|
||||
t.is(route.route, array[index])
|
||||
})
|
||||
})
|
@ -1,76 +0,0 @@
|
||||
import puppeteer from 'puppeteer'
|
||||
|
||||
let browser = null
|
||||
|
||||
export async function start(options = {}) {
|
||||
// https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions
|
||||
browser = await puppeteer.launch(
|
||||
Object.assign(
|
||||
{
|
||||
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
||||
},
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export async function stop() {
|
||||
if (!browser) return
|
||||
await browser.close()
|
||||
}
|
||||
|
||||
export async function page(url) {
|
||||
if (!browser) throw new Error('Please call start() before page(url)')
|
||||
const page = await browser.newPage()
|
||||
await page.goto(url)
|
||||
await page.waitForFunction('!!window.$nuxt')
|
||||
page.html = () =>
|
||||
page.evaluate(() => window.document.documentElement.outerHTML)
|
||||
page.$text = selector => page.$eval(selector, el => el.textContent)
|
||||
page.$$text = selector =>
|
||||
page.$$eval(selector, els => els.map(el => el.textContent))
|
||||
page.$attr = (selector, attr) =>
|
||||
page.$eval(selector, (el, attr) => el.getAttribute(attr), attr)
|
||||
page.$$attr = (selector, attr) =>
|
||||
page.$$eval(
|
||||
selector,
|
||||
(els, attr) => els.map(el => el.getAttribute(attr)),
|
||||
attr
|
||||
)
|
||||
page.$nuxt = await page.evaluateHandle('window.$nuxt')
|
||||
|
||||
page.nuxt = {
|
||||
async navigate(path, waitEnd = true) {
|
||||
const hook = page.evaluate(() => {
|
||||
return new Promise(resolve =>
|
||||
window.$nuxt.$once('routeChanged', resolve)
|
||||
).then(() => new Promise(resolve => setTimeout(resolve, 50)))
|
||||
})
|
||||
await page.evaluate(
|
||||
($nuxt, path) => $nuxt.$router.push(path),
|
||||
page.$nuxt,
|
||||
path
|
||||
)
|
||||
if (waitEnd) await hook
|
||||
return { hook }
|
||||
},
|
||||
routeData() {
|
||||
return page.evaluate($nuxt => {
|
||||
return {
|
||||
path: $nuxt.$route.path,
|
||||
query: $nuxt.$route.query
|
||||
}
|
||||
}, page.$nuxt)
|
||||
},
|
||||
loadingData() {
|
||||
return page.evaluate($nuxt => $nuxt.$loading.$data, page.$nuxt)
|
||||
},
|
||||
errorData() {
|
||||
return page.evaluate($nuxt => $nuxt.nuxt.err, page.$nuxt)
|
||||
},
|
||||
storeState() {
|
||||
return page.evaluate($nuxt => $nuxt.$store.state, page.$nuxt)
|
||||
}
|
||||
}
|
||||
return page
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
import { requireModule } from '../../lib/common/module'
|
||||
|
||||
export function loadConfig(fixture, overrides) {
|
||||
const rootDir = resolve(__dirname, '../fixtures/' + fixture)
|
||||
|
||||
const config = requireModule(resolve(rootDir, 'nuxt.config.js'))
|
||||
|
||||
return Object.assign({ rootDir }, config, overrides)
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
import sinon from 'sinon'
|
||||
|
||||
let context = null
|
||||
|
||||
export function release() {
|
||||
if (context === null) {
|
||||
process.stderr.write(
|
||||
'Console spy context was empty, did a previous test already release it?\n'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (context.log) {
|
||||
console.log = context.log // eslint-disable-line no-console
|
||||
}
|
||||
if (context.info) {
|
||||
console.info = context.info // eslint-disable-line no-console
|
||||
}
|
||||
if (context.warn) {
|
||||
console.warn = context.warn // eslint-disable-line no-console
|
||||
}
|
||||
if (context.error) {
|
||||
console.error = context.error // eslint-disable-line no-console
|
||||
}
|
||||
if (context.stdout) {
|
||||
process.stdout.write = context.stdout
|
||||
}
|
||||
if (context.stderr) {
|
||||
process.stderr.write = context.stderr
|
||||
}
|
||||
|
||||
context = null
|
||||
delete console.spiedInTest // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
export async function intercept(levels, msg, cb) {
|
||||
if (context !== null) {
|
||||
process.stderr.write(
|
||||
'Console spy context was not empty, did a previous test not release it?\n'
|
||||
)
|
||||
}
|
||||
context = {}
|
||||
console.spiedInTest = true // eslint-disable-line no-console
|
||||
|
||||
if (cb === undefined && typeof msg === 'function') {
|
||||
cb = msg
|
||||
msg = undefined
|
||||
|
||||
if (typeof levels === 'string') {
|
||||
msg = levels
|
||||
levels = undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (cb === undefined && msg === undefined && typeof levels === 'function') {
|
||||
cb = levels
|
||||
levels = undefined
|
||||
}
|
||||
|
||||
const all = levels === undefined || levels === {}
|
||||
const spies = {}
|
||||
|
||||
if (all || levels.log) {
|
||||
context.log = console.log // eslint-disable-line no-console
|
||||
spies.log = console.log = sinon.spy() // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if (all || levels.info) {
|
||||
context.info = console.info // eslint-disable-line no-console
|
||||
spies.info = console.info = sinon.spy() // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if (all || levels.warn) {
|
||||
context.warn = console.warn // eslint-disable-line no-console
|
||||
spies.warn = console.warn = sinon.spy() // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if (all || levels.error) {
|
||||
context.error = console.error // eslint-disable-line no-console
|
||||
spies.error = console.error = sinon.spy() // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if (levels && levels.stdout) {
|
||||
context.stdout = process.stdout.write
|
||||
spies.stdout = process.stdout.write = sinon.spy()
|
||||
}
|
||||
|
||||
if (levels && levels.stderr) {
|
||||
context.stderr = process.stderr.write
|
||||
spies.stderr = process.stderr.write = sinon.spy()
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
if (msg) {
|
||||
if (context.stdout) {
|
||||
context.stdout(` ${msg}`)
|
||||
} else {
|
||||
process.stdout.write(` ${msg}`)
|
||||
}
|
||||
}
|
||||
|
||||
await cb()
|
||||
|
||||
release()
|
||||
|
||||
if (msg) {
|
||||
process.stdout.write('\n')
|
||||
}
|
||||
}
|
||||
|
||||
return spies
|
||||
}
|
||||
|
||||
export async function interceptLog(msg, cb) {
|
||||
const { log } = await intercept({ log: true }, msg, cb)
|
||||
return log
|
||||
}
|
||||
|
||||
export async function interceptInfo(msg, cb) {
|
||||
const { info } = await intercept({ info: true }, msg, cb)
|
||||
return info
|
||||
}
|
||||
|
||||
export async function interceptWarn(msg, cb) {
|
||||
const { warn } = await intercept({ warn: true }, msg, cb)
|
||||
return warn
|
||||
}
|
||||
|
||||
export async function interceptError(msg, cb) {
|
||||
const { error } = await intercept({ error: true }, msg, cb)
|
||||
return error
|
||||
}
|
||||
|
||||
export async function interceptStdout(msg, cb) {
|
||||
const { stdout } = await intercept({ stdout: true }, msg, cb)
|
||||
return stdout
|
||||
}
|
||||
|
||||
export async function interceptStderr(msg, cb) {
|
||||
const { stderr } = await intercept({ stderr: true }, msg, cb)
|
||||
return stderr
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import test from 'ava'
|
||||
import { resolve } from 'path'
|
||||
import { Nuxt, Builder } from '..'
|
||||
|
||||
test('Nuxt.js Class', t => {
|
||||
t.is(typeof Nuxt, 'function')
|
||||
})
|
||||
|
||||
test('Nuxt.js Instance', async t => {
|
||||
const nuxt = new Nuxt({
|
||||
dev: true,
|
||||
rootDir: resolve(__dirname, 'fixtures', 'empty')
|
||||
})
|
||||
t.is(typeof nuxt, 'object')
|
||||
t.is(nuxt.options.dev, true)
|
||||
t.is(typeof nuxt._ready.then, 'function')
|
||||
await nuxt.ready()
|
||||
t.is(nuxt.initialized, true)
|
||||
})
|
||||
|
||||
test('Fail to build when no pages/ directory but is in the parent', t => {
|
||||
const nuxt = new Nuxt({
|
||||
dev: false,
|
||||
rootDir: resolve(__dirname, 'fixtures', 'empty', 'pages')
|
||||
})
|
||||
return new Builder(nuxt).build().catch(err => {
|
||||
let s = String(err)
|
||||
t.true(s.includes('No `pages` directory found'))
|
||||
t.true(
|
||||
s.includes('Did you mean to run `nuxt` in the parent (`../`) directory?')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('Fail to build when no pages/ directory', t => {
|
||||
const nuxt = new Nuxt({
|
||||
dev: false,
|
||||
rootDir: resolve(__dirname)
|
||||
})
|
||||
return new Builder(nuxt).build().catch(err => {
|
||||
let s = String(err)
|
||||
t.true(s.includes("Couldn't find a `pages` directory"))
|
||||
t.true(s.includes('Please create one under the project root'))
|
||||
})
|
||||
})
|
@ -1,83 +0,0 @@
|
||||
import { normalize } from 'path'
|
||||
|
||||
import test from 'ava'
|
||||
import rp from 'request-promise-native'
|
||||
|
||||
import { Nuxt, Builder } from '..'
|
||||
|
||||
import { intercept } from './helpers/console'
|
||||
import { loadConfig } from './helpers/config'
|
||||
|
||||
const port = 4006
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let builder = null
|
||||
let buildSpies = null
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const config = loadConfig('module', { dev: false })
|
||||
|
||||
nuxt = new Nuxt(config)
|
||||
builder = new Builder(nuxt)
|
||||
|
||||
buildSpies = await intercept({ log: true, error: true }, async () => {
|
||||
await builder.build()
|
||||
await nuxt.listen(port, 'localhost')
|
||||
})
|
||||
|
||||
t.true(buildSpies.log.calledWithMatch('DONE'))
|
||||
t.true(buildSpies.log.calledWithMatch('OPEN'))
|
||||
})
|
||||
|
||||
test.serial('Plugin', async t => {
|
||||
t.true(
|
||||
normalize(nuxt.options.plugins[0].src).includes(
|
||||
normalize('fixtures/module/.nuxt/basic.reverse.')
|
||||
),
|
||||
'plugin added to config'
|
||||
)
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('<h1>TXUN</h1>'), 'plugin works')
|
||||
})
|
||||
|
||||
test.serial('Layout', async t => {
|
||||
t.true(
|
||||
nuxt.options.layouts.layout.includes('layout'),
|
||||
'layout added to config'
|
||||
)
|
||||
|
||||
const { html } = await nuxt.renderRoute('/layout')
|
||||
t.true(html.includes('<h1>Module Layouts</h1>'), 'layout works')
|
||||
})
|
||||
|
||||
test.serial('Hooks', async t => {
|
||||
t.is(nuxt.__module_hook, 1)
|
||||
t.is(nuxt.__renderer_hook, 2)
|
||||
t.is(nuxt.__builder_hook, 3)
|
||||
})
|
||||
|
||||
test.serial('Hooks - Functional', async t => {
|
||||
t.true(nuxt.__ready_called__)
|
||||
t.true(builder.__build_done__)
|
||||
})
|
||||
|
||||
test.serial('Hooks - Error', async t => {
|
||||
t.true(buildSpies.error.calledWithMatch(/build:extendRoutes/))
|
||||
})
|
||||
|
||||
test('Middleware', async t => {
|
||||
let response = await rp(url('/api'))
|
||||
t.is(response, 'It works!', '/api response is correct')
|
||||
})
|
||||
|
||||
test('Hooks - Use external middleware before render', async t => {
|
||||
let response = await rp(url('/use-middleware'))
|
||||
t.is(response, 'Use external middleware')
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
@ -1,84 +0,0 @@
|
||||
import test from 'ava'
|
||||
import { Nuxt, Builder } from '..'
|
||||
import { interceptLog, release } from './helpers/console'
|
||||
import { loadConfig } from './helpers/config'
|
||||
|
||||
let nuxt = null
|
||||
|
||||
const port = 4012
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
const renderRoute = async _url => {
|
||||
const window = await nuxt.renderAndGetWindow(url(_url))
|
||||
const head = window.document.head.innerHTML
|
||||
const html = window.document.body.innerHTML
|
||||
return { window, head, html }
|
||||
}
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.serial('Init Nuxt.js', async t => {
|
||||
const config = loadConfig('spa')
|
||||
|
||||
const logSpy = await interceptLog(async () => {
|
||||
nuxt = new Nuxt(config)
|
||||
await new Builder(nuxt).build()
|
||||
await nuxt.listen(port, 'localhost')
|
||||
})
|
||||
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
t.true(logSpy.calledWithMatch('OPEN'))
|
||||
})
|
||||
|
||||
test.serial('/ (basic spa)', async t => {
|
||||
const logSpy = await interceptLog()
|
||||
const { html } = await renderRoute('/')
|
||||
t.true(html.includes('Hello SPA!'))
|
||||
release()
|
||||
t.true(logSpy.withArgs('created').notCalled)
|
||||
t.true(logSpy.withArgs('mounted').calledOnce)
|
||||
})
|
||||
|
||||
test.serial('/custom (custom layout)', async t => {
|
||||
const logSpy = await interceptLog()
|
||||
const { html } = await renderRoute('/custom')
|
||||
t.true(html.includes('Custom layout'))
|
||||
release()
|
||||
t.true(logSpy.withArgs('created').calledOnce)
|
||||
t.true(logSpy.withArgs('mounted').calledOnce)
|
||||
})
|
||||
|
||||
test.serial('/custom (not default layout)', async t => {
|
||||
const logSpy = await interceptLog()
|
||||
const { head } = await renderRoute('/custom')
|
||||
t.false(head.includes('src="/_nuxt/layouts/default.'))
|
||||
release()
|
||||
t.true(logSpy.withArgs('created').calledOnce)
|
||||
t.true(logSpy.withArgs('mounted').calledOnce)
|
||||
})
|
||||
|
||||
test.serial('/custom (call mounted and created once)', async t => {
|
||||
const logSpy = await interceptLog()
|
||||
await renderRoute('/custom')
|
||||
release()
|
||||
t.true(logSpy.withArgs('created').calledOnce)
|
||||
t.true(logSpy.withArgs('mounted').calledOnce)
|
||||
})
|
||||
|
||||
test.serial('/mounted', async t => {
|
||||
const { html } = await renderRoute('/mounted')
|
||||
|
||||
t.true(html.includes('<h1>Test: updated</h1>'))
|
||||
})
|
||||
|
||||
test('/_nuxt/ (access publicPath in spa mode)', async t => {
|
||||
const { response: { statusCode, statusMessage } } = await t.throws(
|
||||
renderRoute('/_nuxt/')
|
||||
)
|
||||
t.is(statusCode, 404)
|
||||
t.is(statusMessage, 'ResourceNotFound')
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
15
test/unit/basic.config.defaults.test.js
Normal file
15
test/unit/basic.config.defaults.test.js
Normal file
@ -0,0 +1,15 @@
|
||||
import { resolve } from 'path'
|
||||
import { Nuxt, Options } from '../../'
|
||||
import { version } from '../../package.json'
|
||||
|
||||
describe('basic config defaults', () => {
|
||||
test('Nuxt.version is same as package', () => {
|
||||
expect(Nuxt.version).toBe(version)
|
||||
})
|
||||
|
||||
test('modulesDir uses /node_modules as default if not set', async () => {
|
||||
const options = Options.from({})
|
||||
const currentNodeModulesDir = resolve(__dirname, '..', '..', 'node_modules')
|
||||
expect(options.modulesDir.includes(currentNodeModulesDir)).toBe(true)
|
||||
})
|
||||
})
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user