@@ -87,9 +87,10 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ["**/__fixtures__/**"],
|
files: ["test/**", "**/__fixtures__/**"],
|
||||||
rules: {
|
rules: {
|
||||||
"import/no-default-export": "off",
|
"import/no-default-export": "off",
|
||||||
|
"require-await": "off",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
40
.github/workflows/main.yml
vendored
40
.github/workflows/main.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
|||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}
|
key: ${{ github.sha }}
|
||||||
|
|
||||||
build_and_test_pkgs:
|
testBlitzPackages:
|
||||||
name: Blitz Packages Tests
|
name: Blitz Packages Tests
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -108,7 +108,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
|
||||||
build_and_test_examples:
|
testBlitzExamples:
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
name: Blitz Example Apps Tests
|
name: Blitz Example Apps Tests
|
||||||
strategy:
|
strategy:
|
||||||
@@ -193,6 +193,32 @@ jobs:
|
|||||||
- run: node run-tests.js --timings --type unit -g 1/1
|
- run: node run-tests.js --timings --type unit -g 1/1
|
||||||
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||||
|
|
||||||
|
testIntegrationBlitz:
|
||||||
|
name: Blitz - Test Integration
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
env:
|
||||||
|
NEXT_TELEMETRY_DISABLED: 1
|
||||||
|
NEXT_TEST_JOB: 1
|
||||||
|
HEADLESS: true
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
steps:
|
||||||
|
- run: echo ${{needs.build.outputs.docsChange}}
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||||
|
id: restore-build
|
||||||
|
with:
|
||||||
|
path: ./*
|
||||||
|
key: ${{ github.sha }}
|
||||||
|
|
||||||
|
# TODO: remove after we fix watchpack watching too much
|
||||||
|
- run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
|
||||||
|
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||||
|
|
||||||
|
- run: xvfb-run node nextjs/run-tests.js -c 3
|
||||||
|
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||||
|
|
||||||
testIntegration:
|
testIntegration:
|
||||||
name: Nextjs - Test Integration
|
name: Nextjs - Test Integration
|
||||||
defaults:
|
defaults:
|
||||||
@@ -259,7 +285,15 @@ jobs:
|
|||||||
testsPass:
|
testsPass:
|
||||||
name: thank you, next
|
name: thank you, next
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [checkPrecompiled, testIntegration, testUnit]
|
needs:
|
||||||
|
[
|
||||||
|
checkPrecompiled,
|
||||||
|
testIntegration,
|
||||||
|
testIntegrationBlitz,
|
||||||
|
testUnit,
|
||||||
|
testBlitzPackages,
|
||||||
|
testBlitzExamples,
|
||||||
|
]
|
||||||
steps:
|
steps:
|
||||||
- run: exit 0
|
- run: exit 0
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
.log
|
.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.jest-*
|
.jest-*
|
||||||
lib
|
packages/cli/lib
|
||||||
node_modules
|
node_modules
|
||||||
reports
|
reports
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -26,4 +26,24 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
test: "./test/**/*",
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
modules: false,
|
||||||
|
// loose: true,
|
||||||
|
exclude: [
|
||||||
|
"@babel/plugin-transform-async-to-generator",
|
||||||
|
"@babel/plugin-transform-regenerator",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"blitz/babel",
|
||||||
|
],
|
||||||
|
plugins: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,25 @@
|
|||||||
const withMonorepoBuildTooling = require("@preconstruct/next")
|
|
||||||
const {sessionMiddleware, simpleRolesIsAuthorized} = require("blitz")
|
const {sessionMiddleware, simpleRolesIsAuthorized} = require("blitz")
|
||||||
const withBundleAnalyzer = require("@next/bundle-analyzer")({
|
const withBundleAnalyzer = require("@next/bundle-analyzer")({
|
||||||
enabled: process.env.ANALYZE === "true",
|
enabled: process.env.ANALYZE === "true",
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = withMonorepoBuildTooling(
|
module.exports = withBundleAnalyzer({
|
||||||
withBundleAnalyzer({
|
middleware: [
|
||||||
middleware: [
|
sessionMiddleware({
|
||||||
sessionMiddleware({
|
isAuthorized: simpleRolesIsAuthorized,
|
||||||
isAuthorized: simpleRolesIsAuthorized,
|
// sessionExpiryMinutes: 4,
|
||||||
// sessionExpiryMinutes: 4,
|
}),
|
||||||
}),
|
],
|
||||||
],
|
cli: {
|
||||||
cli: {
|
clearConsoleOnBlitzDev: false,
|
||||||
clearConsoleOnBlitzDev: false,
|
},
|
||||||
},
|
log: {
|
||||||
log: {
|
// level: "trace",
|
||||||
// level: "trace",
|
},
|
||||||
},
|
experimental: {
|
||||||
experimental: {
|
isomorphicResolverImports: false,
|
||||||
isomorphicResolverImports: false,
|
},
|
||||||
},
|
/*
|
||||||
/*
|
|
||||||
webpack: (config, {buildId, dev, isServer, defaultLoaders, webpack}) => {
|
webpack: (config, {buildId, dev, isServer, defaultLoaders, webpack}) => {
|
||||||
// Note: we provide webpack above so you should not `require` it
|
// Note: we provide webpack above so you should not `require` it
|
||||||
// Perform customizations to webpack config
|
// Perform customizations to webpack config
|
||||||
@@ -34,5 +32,4 @@ module.exports = withMonorepoBuildTooling(
|
|||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const {sessionMiddleware, simpleRolesIsAuthorized} = require("blitz")
|
const {sessionMiddleware, simpleRolesIsAuthorized} = require("blitz")
|
||||||
const withMonorepoBuildTooling = require("@preconstruct/next")
|
|
||||||
|
|
||||||
module.exports = withMonorepoBuildTooling({
|
module.exports = {
|
||||||
middleware: [
|
middleware: [
|
||||||
sessionMiddleware({
|
sessionMiddleware({
|
||||||
isAuthorized: simpleRolesIsAuthorized,
|
isAuthorized: simpleRolesIsAuthorized,
|
||||||
@@ -15,4 +14,4 @@ module.exports = withMonorepoBuildTooling({
|
|||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
})
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
const { sessionMiddleware, simpleRolesIsAuthorized } = require("blitz")
|
const { sessionMiddleware, simpleRolesIsAuthorized } = require("blitz")
|
||||||
const withMonorepoBuildTooling = require("@preconstruct/next")
|
|
||||||
const { GraphQLClient, gql } = require("graphql-request")
|
const { GraphQLClient, gql } = require("graphql-request")
|
||||||
|
|
||||||
const graphQLClient = new GraphQLClient("https://graphql.fauna.com/graphql", {
|
const graphQLClient = new GraphQLClient("https://graphql.fauna.com/graphql", {
|
||||||
@@ -18,7 +17,7 @@ const normalizeSession = (faunaSession) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = withMonorepoBuildTooling({
|
module.exports = {
|
||||||
middleware: [
|
middleware: [
|
||||||
sessionMiddleware({
|
sessionMiddleware({
|
||||||
isAuthorized: simpleRolesIsAuthorized,
|
isAuthorized: simpleRolesIsAuthorized,
|
||||||
@@ -159,4 +158,4 @@ module.exports = withMonorepoBuildTooling({
|
|||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
})
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
const withMonorepoBuildTooling = require("@preconstruct/next")
|
module.exports = {
|
||||||
|
|
||||||
module.exports = withMonorepoBuildTooling({
|
|
||||||
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
|
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
|
||||||
// Note: we provide webpack above so you should not `require` it
|
// Note: we provide webpack above so you should not `require` it
|
||||||
// Perform customizations to webpack config
|
// Perform customizations to webpack config
|
||||||
@@ -12,4 +10,4 @@ module.exports = withMonorepoBuildTooling({
|
|||||||
// Important: return the modified config
|
// Important: return the modified config
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
const withMonorepoBuildTooling = require("@preconstruct/next")
|
module.exports = {
|
||||||
|
|
||||||
module.exports = withMonorepoBuildTooling({
|
|
||||||
middleware: [],
|
middleware: [],
|
||||||
/* Uncomment this to customize the webpack config
|
/* Uncomment this to customize the webpack config
|
||||||
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
|
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
|
||||||
@@ -10,4 +8,4 @@ module.exports = withMonorepoBuildTooling({
|
|||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
})
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
const withMonorepoBuildTooling = require("@preconstruct/next")
|
module.exports = {
|
||||||
|
|
||||||
module.exports = withMonorepoBuildTooling({
|
|
||||||
middleware: [
|
middleware: [
|
||||||
(req, res, next) => {
|
(req, res, next) => {
|
||||||
res.blitzCtx.referer = req.headers.referer
|
res.blitzCtx.referer = req.headers.referer
|
||||||
@@ -24,4 +22,4 @@ module.exports = withMonorepoBuildTooling({
|
|||||||
// // Important: return the modified config
|
// // Important: return the modified config
|
||||||
// return config
|
// return config
|
||||||
// },
|
// },
|
||||||
})
|
}
|
||||||
|
|||||||
37
jest-unit.config.js
Normal file
37
jest-unit.config.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const {jsWithBabel: tsjPreset} = require("ts-jest/preset")
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
testEnvironment: "node",
|
||||||
|
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||||
|
modulePathIgnorePatterns: ["<rootDir>/tmp", "<rootDir>/dist", "<rootDir>/templates"],
|
||||||
|
moduleNameMapper: {},
|
||||||
|
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
|
||||||
|
transform: {
|
||||||
|
...tsjPreset.transform,
|
||||||
|
},
|
||||||
|
transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"],
|
||||||
|
testMatch: ["<rootDir>/**/*.(spec|test).{ts,tsx,js,jsx}"],
|
||||||
|
testURL: "http://localhost",
|
||||||
|
// watchPlugins: [
|
||||||
|
// require.resolve("jest-watch-typeahead/filename"),
|
||||||
|
// require.resolve("jest-watch-typeahead/testname"),
|
||||||
|
// ],
|
||||||
|
coverageReporters: ["json", "lcov", "text", "clover"],
|
||||||
|
// collectCoverage: !!`Boolean(process.env.CI)`,
|
||||||
|
collectCoverageFrom: ["src/**/*.{ts,tsx,js,jsx}"],
|
||||||
|
coveragePathIgnorePatterns: ["/templates/"],
|
||||||
|
// coverageThreshold: {
|
||||||
|
// global: {
|
||||||
|
// branches: 100,
|
||||||
|
// functions: 100,
|
||||||
|
// lines: 100,
|
||||||
|
// statements: 100,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
globals: {
|
||||||
|
"ts-jest": {
|
||||||
|
tsconfig: __dirname + "/tsconfig.test.json",
|
||||||
|
isolatedModules: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,37 +1,10 @@
|
|||||||
const {jsWithBabel: tsjPreset} = require("ts-jest/preset")
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
testEnvironment: "node",
|
testMatch: ["**/*.test.js", "**/*.test.ts"],
|
||||||
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
|
verbose: true,
|
||||||
modulePathIgnorePatterns: ["<rootDir>/tmp", "<rootDir>/dist", "<rootDir>/templates"],
|
rootDir: "test",
|
||||||
moduleNameMapper: {},
|
modulePaths: ["<rootDir>/lib"],
|
||||||
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
|
globalSetup: "<rootDir>/jest-global-setup.js",
|
||||||
transform: {
|
globalTeardown: "<rootDir>/jest-global-teardown.js",
|
||||||
...tsjPreset.transform,
|
setupFilesAfterEnv: ["<rootDir>/jest-setup-after-env.js"],
|
||||||
},
|
testEnvironment: "<rootDir>/jest-environment.js",
|
||||||
transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"],
|
|
||||||
testMatch: ["<rootDir>/**/*.(spec|test).{ts,tsx,js,jsx}"],
|
|
||||||
testURL: "http://localhost",
|
|
||||||
// watchPlugins: [
|
|
||||||
// require.resolve("jest-watch-typeahead/filename"),
|
|
||||||
// require.resolve("jest-watch-typeahead/testname"),
|
|
||||||
// ],
|
|
||||||
coverageReporters: ["json", "lcov", "text", "clover"],
|
|
||||||
// collectCoverage: !!`Boolean(process.env.CI)`,
|
|
||||||
collectCoverageFrom: ["src/**/*.{ts,tsx,js,jsx}"],
|
|
||||||
coveragePathIgnorePatterns: ["/templates/"],
|
|
||||||
// coverageThreshold: {
|
|
||||||
// global: {
|
|
||||||
// branches: 100,
|
|
||||||
// functions: 100,
|
|
||||||
// lines: 100,
|
|
||||||
// statements: 100,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
globals: {
|
|
||||||
"ts-jest": {
|
|
||||||
tsconfig: __dirname + "/tsconfig.test.json",
|
|
||||||
isolatedModules: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"dev": "taskr",
|
"dev": "taskr",
|
||||||
"release": "taskr release",
|
"release": "taskr release",
|
||||||
"prepublish": "npm run release && yarn types",
|
"prepublish": "npm run release && yarn types",
|
||||||
"types": "tsc --declaration --emitDeclarationOnly --declarationDir dist",
|
"types": "rimraf \"dist/**/*.d.ts\" && tsc --declaration --emitDeclarationOnly --declarationDir dist",
|
||||||
"typescript": "tsc --noEmit --declaration",
|
"typescript": "tsc --noEmit --declaration",
|
||||||
"ncc-compiled": "ncc cache clean && taskr ncc"
|
"ncc-compiled": "ncc cache clean && taskr ncc"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ async function main() {
|
|||||||
tests = (
|
tests = (
|
||||||
await glob('**/*.test.js', {
|
await glob('**/*.test.js', {
|
||||||
nodir: true,
|
nodir: true,
|
||||||
cwd: path.join(__dirname, 'test'),
|
cwd: path.join(process.cwd(), 'test'),
|
||||||
})
|
})
|
||||||
).filter((test) => {
|
).filter((test) => {
|
||||||
// only include the specified type
|
// only include the specified type
|
||||||
@@ -79,7 +79,7 @@ async function main() {
|
|||||||
if (outputTimings && groupArg) {
|
if (outputTimings && groupArg) {
|
||||||
console.log('Fetching previous timings data')
|
console.log('Fetching previous timings data')
|
||||||
try {
|
try {
|
||||||
const timingsFile = path.join(__dirname, 'test-timings.json')
|
const timingsFile = path.join(process.cwd(), 'test-timings.json')
|
||||||
try {
|
try {
|
||||||
prevTimings = JSON.parse(await fs.readFile(timingsFile, 'utf8'))
|
prevTimings = JSON.parse(await fs.readFile(timingsFile, 'utf8'))
|
||||||
console.log('Loaded test timings from disk successfully')
|
console.log('Loaded test timings from disk successfully')
|
||||||
@@ -234,7 +234,7 @@ async function main() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (i < NUM_RETRIES) {
|
if (i < NUM_RETRIES) {
|
||||||
try {
|
try {
|
||||||
const testDir = path.dirname(path.join(__dirname, test))
|
const testDir = path.dirname(path.join(process.cwd(), test))
|
||||||
console.log('Cleaning test files at', testDir)
|
console.log('Cleaning test files at', testDir)
|
||||||
await exec(`git clean -fdx "${testDir}"`)
|
await exec(`git clean -fdx "${testDir}"`)
|
||||||
await exec(`git checkout "${testDir}"`)
|
await exec(`git checkout "${testDir}"`)
|
||||||
|
|||||||
18
package.json
18
package.json
@@ -24,17 +24,23 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "husky install && patch-package && symlink-dir node_modules/@blitzjs/next node_modules/next",
|
"postinstall": "husky install && patch-package && symlink-dir node_modules/@blitzjs/next node_modules/next",
|
||||||
|
"wait:nextjs": "wait-on -d 1000 nextjs/packages/next/dist/build/index.js",
|
||||||
|
"wait:nextjs-types": "wait-on -d 1000 nextjs/packages/next/dist/build/index.d.ts",
|
||||||
"dev:nextjs": "yarn workspace @blitzjs/next dev",
|
"dev:nextjs": "yarn workspace @blitzjs/next dev",
|
||||||
"dev:tsc": "tsc --watch --pretty --preserveWatchOutput",
|
"dev:nextjs-types": "yarn wait:nextjs && yarn workspace @blitzjs/next types && echo 'Finished building nextjs types'",
|
||||||
"dev:cli": "yarn workspace @blitzjs/cli dev",
|
"dev:blitz": "preconstruct watch",
|
||||||
|
"dev:tsc": "yarn dev:nextjs-types && tsc --watch --pretty --preserveWatchOutput",
|
||||||
|
"dev:cli": "yarn wait:nextjs && yarn workspace @blitzjs/cli dev",
|
||||||
"dev:templates": "yarn workspace @blitzjs/generator dev",
|
"dev:templates": "yarn workspace @blitzjs/generator dev",
|
||||||
"dev": "yarn workspace @blitzjs/next prepublish && preconstruct dev && concurrently --names \"typecheck,cli,templates\" -c \"blue,green,yellow,magenta\" -p \"{name}\" \"npm:dev:tsc\" \"npm:dev:cli\" \"npm:dev:templates\"",
|
"dev": "concurrently --names \"nextjs,blitz,typecheck,cli,templates\" -c \"magenta,cyan,green,yellow,black\" -p \"{name}\" \"npm:dev:nextjs\" \"npm:dev:blitz\" \"npm:dev:tsc\" \"npm:dev:cli\" \"npm:dev:templates\"",
|
||||||
"build:nextjs": "yarn workspace @blitzjs/next prepublish",
|
"build:nextjs": "yarn workspace @blitzjs/next prepublish",
|
||||||
"build": "yarn build:nextjs && cross-env BLITZ_PROD_BUILD=true preconstruct build && ultra -r --filter \"packages/*\" buildpkg && tsc",
|
"build": "yarn build:nextjs && cross-env BLITZ_PROD_BUILD=true preconstruct build && ultra -r --filter \"packages/*\" buildpkg && tsc",
|
||||||
"lint": "eslint --ext \".js,.ts,.tsx\" .",
|
"lint": "eslint --ext \".js,.ts,.tsx\" .",
|
||||||
"link-cli": "yarn workspace blitz link",
|
"link-cli": "yarn workspace blitz link",
|
||||||
"unlink-cli": "yarn workspace blitz unlink",
|
"unlink-cli": "yarn workspace blitz unlink",
|
||||||
"test": "yarn run lint && yarn run build && ultra -r test",
|
"test": "yarn run lint && yarn run build && ultra -r test",
|
||||||
|
"testheadless": "cross-env HEADLESS=true yarn test:integration",
|
||||||
|
"test:integration": "jest --runInBand",
|
||||||
"test:packages": "yarn run build && yarn testonly:packages",
|
"test:packages": "yarn run build && yarn testonly:packages",
|
||||||
"test:examples": "yarn run build && yarn testonly:examples",
|
"test:examples": "yarn run build && yarn testonly:examples",
|
||||||
"test:nextjs-size": "yarn --cwd nextjs testheadless --testPathPattern \"integration/(build-output|size-limit|fallback-modules)\"",
|
"test:nextjs-size": "yarn --cwd nextjs testheadless --testPathPattern \"integration/(build-output|size-limit|fallback-modules)\"",
|
||||||
@@ -77,8 +83,7 @@
|
|||||||
"@babel/preset-typescript": "7.12.7",
|
"@babel/preset-typescript": "7.12.7",
|
||||||
"@juanm04/cpx": "2.0.0",
|
"@juanm04/cpx": "2.0.0",
|
||||||
"@manypkg/cli": "0.17.0",
|
"@manypkg/cli": "0.17.0",
|
||||||
"@preconstruct/cli": "2.0.5",
|
"@preconstruct/cli": "2.0.7",
|
||||||
"@preconstruct/next": "2.0.0",
|
|
||||||
"@rollup/pluginutils": "4.1.0",
|
"@rollup/pluginutils": "4.1.0",
|
||||||
"@size-limit/preset-small-lib": "4.9.2",
|
"@size-limit/preset-small-lib": "4.9.2",
|
||||||
"@testing-library/jest-dom": "5.11.9",
|
"@testing-library/jest-dom": "5.11.9",
|
||||||
@@ -95,6 +100,7 @@
|
|||||||
"@types/flush-write-stream": "1.0.0",
|
"@types/flush-write-stream": "1.0.0",
|
||||||
"@types/from2": "2.3.0",
|
"@types/from2": "2.3.0",
|
||||||
"@types/fs-extra": "8.1.0",
|
"@types/fs-extra": "8.1.0",
|
||||||
|
"@types/get-port": "4.2.0",
|
||||||
"@types/gulp-if": "0.0.33",
|
"@types/gulp-if": "0.0.33",
|
||||||
"@types/htmlescape": "^1.1.1",
|
"@types/htmlescape": "^1.1.1",
|
||||||
"@types/ink-spinner": "3.0.0",
|
"@types/ink-spinner": "3.0.0",
|
||||||
@@ -153,6 +159,7 @@
|
|||||||
"eslint-plugin-simple-import-sort": "7.0.0",
|
"eslint-plugin-simple-import-sort": "7.0.0",
|
||||||
"eslint-plugin-unicorn": "26.0.1",
|
"eslint-plugin-unicorn": "26.0.1",
|
||||||
"eslint_d": "10.0.0",
|
"eslint_d": "10.0.0",
|
||||||
|
"get-port": "5.1.1",
|
||||||
"husky": "5.1.2",
|
"husky": "5.1.2",
|
||||||
"jest": "27.0.0-next.5",
|
"jest": "27.0.0-next.5",
|
||||||
"lerna": "4.0.0",
|
"lerna": "4.0.0",
|
||||||
@@ -179,6 +186,7 @@
|
|||||||
"stdout-stderr": "0.1.13",
|
"stdout-stderr": "0.1.13",
|
||||||
"strip-ansi": "6.0.0",
|
"strip-ansi": "6.0.0",
|
||||||
"test-listen": "1.1.0",
|
"test-listen": "1.1.0",
|
||||||
|
"tree-kill": "1.2.2",
|
||||||
"ts-jest": "27.0.0-next.10",
|
"ts-jest": "27.0.0-next.10",
|
||||||
"tslib": "2.1.0",
|
"tslib": "2.1.0",
|
||||||
"typescript": "4.1.5",
|
"typescript": "4.1.5",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: '../../jest.config.js',
|
preset: '../../jest-unit.config.js',
|
||||||
testEnvironment: 'jest-environment-jsdom',
|
testEnvironment: 'jest-environment-jsdom',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import RewriteImports from './rewrite-imports';
|
|||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default function preset(_api: any, options = {}) {
|
export default function preset(_api: any, options = {}) {
|
||||||
// const isTest = _api.env('test');
|
// const isTest = _api.env('test');
|
||||||
const isRunningInJest = Boolean(process.env.JEST_WORKER_ID);
|
const isRunningInJest =
|
||||||
|
process.env.JEST_WORKER_ID && !process.env.__NEXT_TEST_MODE;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
presets: [[require('next/babel'), options]],
|
presets: [[require('next/babel'), options]],
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
// collectCoverage: !!`Boolean(process.env.CI)`,
|
// collectCoverage: !!`Boolean(process.env.CI)`,
|
||||||
modulePathIgnorePatterns: ["<rootDir>/tmp", "<rootDir>/lib", "<rootDir>/commands/.test"],
|
modulePathIgnorePatterns: ["<rootDir>/tmp", "<rootDir>/lib", "<rootDir>/commands/.test"],
|
||||||
testPathIgnorePatterns: ["src/commands/test.ts", "test/commands/.test"],
|
testPathIgnorePatterns: ["src/commands/test.ts", "test/commands/.test"],
|
||||||
|
|||||||
@@ -40,7 +40,10 @@ export class Dev extends Command {
|
|||||||
const {getConfig} = await import("@blitzjs/config")
|
const {getConfig} = await import("@blitzjs/config")
|
||||||
|
|
||||||
const blitzConfig = getConfig()
|
const blitzConfig = getConfig()
|
||||||
if (blitzConfig.cli?.clearConsoleOnBlitzDev !== false) {
|
if (
|
||||||
|
blitzConfig.cli?.clearConsoleOnBlitzDev !== false &&
|
||||||
|
!process.env.BLITZ_TEST_ENVIRONMENT
|
||||||
|
) {
|
||||||
const {log} = await import("@blitzjs/display")
|
const {log} = await import("@blitzjs/display")
|
||||||
log.clearConsole()
|
log.clearConsole()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {readJSON} from "fs-extra"
|
import {existsSync, readJSON} from "fs-extra"
|
||||||
import {resolve} from "path"
|
import {resolve} from "path"
|
||||||
import pkgDir from "pkg-dir"
|
import pkgDir from "pkg-dir"
|
||||||
|
|
||||||
@@ -54,6 +54,10 @@ export const isBlitzRoot = async (): Promise<{
|
|||||||
if (err.code === "ENOENT") {
|
if (err.code === "ENOENT") {
|
||||||
const out = await checkParent()
|
const out = await checkParent()
|
||||||
|
|
||||||
|
if (existsSync("./blitz.config.js") || existsSync("./blitz.config.ts")) {
|
||||||
|
return {err: false}
|
||||||
|
}
|
||||||
|
|
||||||
if (out === false) {
|
if (out === false) {
|
||||||
return {
|
return {
|
||||||
err: true,
|
err: true,
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import pkgDir from "pkg-dir"
|
|||||||
const debug = require("debug")("blitz:config")
|
const debug = require("debug")("blitz:config")
|
||||||
|
|
||||||
export function getProjectRoot() {
|
export function getProjectRoot() {
|
||||||
return pkgDir.sync() || process.cwd()
|
return (
|
||||||
|
path.dirname(path.resolve(process.cwd(), "blitz.config.js")) || pkgDir.sync() || process.cwd()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlitzConfig extends Record<string, unknown> {
|
export interface BlitzConfig extends Record<string, unknown> {
|
||||||
@@ -40,11 +42,16 @@ export const getConfig = (reload?: boolean): BlitzConfig => {
|
|||||||
|
|
||||||
const {PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_SERVER} = require("next/constants")
|
const {PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_SERVER} = require("next/constants")
|
||||||
|
|
||||||
const pkgJson = readJSONSync(join(getProjectRoot(), "package.json"))
|
let pkgJson: any
|
||||||
|
|
||||||
|
const pkgJsonPath = join(getProjectRoot(), "package.json")
|
||||||
|
if (existsSync(pkgJsonPath)) {
|
||||||
|
pkgJson = readJSONSync(join(getProjectRoot(), "package.json"))
|
||||||
|
}
|
||||||
|
|
||||||
let blitzConfig = {
|
let blitzConfig = {
|
||||||
_meta: {
|
_meta: {
|
||||||
packageName: pkgJson.name,
|
packageName: pkgJson?.name,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,10 +96,10 @@ export const getConfig = (reload?: boolean): BlitzConfig => {
|
|||||||
...loadedNextConfig,
|
...loadedNextConfig,
|
||||||
...loadedBlitzConfig,
|
...loadedBlitzConfig,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (error) {
|
||||||
// https://github.com/blitz-js/blitz/issues/2080
|
// https://github.com/blitz-js/blitz/issues/2080
|
||||||
if (!process.env.JEST_WORKER_ID) {
|
if (!process.env.JEST_WORKER_ID) {
|
||||||
console.error("Failed to load config in getConfig()")
|
console.error("Failed to load config in getConfig()", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
testEnvironment: "jest-environment-jsdom",
|
testEnvironment: "jest-environment-jsdom",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "../../jest.config.js",
|
preset: "../../jest-unit.config.js",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
diff --git a/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js b/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js
|
|
||||||
index 7e40755..fde60cc 100644
|
|
||||||
--- a/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js
|
|
||||||
+++ b/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js
|
|
||||||
@@ -1770,6 +1770,8 @@ let getRollupConfig = (pkg, entrypoints, aliases, type, reportTransformedFile) =
|
|
||||||
external.push(...builtInModules);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ external.push('next', 'react', '@babel/core', 'prettier')
|
|
||||||
+
|
|
||||||
let input = {};
|
|
||||||
entrypoints.forEach(entrypoint => {
|
|
||||||
input[path__default.relative(pkg.directory, path__default.join(entrypoint.directory, "dist", getNameForDistForEntrypoint(entrypoint)))] = entrypoint.source;
|
|
||||||
22
patches/@preconstruct+cli+2.0.7.patch
Normal file
22
patches/@preconstruct+cli+2.0.7.patch
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
diff --git a/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js b/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js
|
||||||
|
index 972d57b..e6bc64b 100644
|
||||||
|
--- a/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js
|
||||||
|
+++ b/node_modules/@preconstruct/cli/cli/dist/cli.cjs.dev.js
|
||||||
|
@@ -166,7 +166,7 @@ function format(args, messageType, scope) {
|
||||||
|
info: chalk.cyan("info"),
|
||||||
|
none: ""
|
||||||
|
}[messageType];
|
||||||
|
- let fullPrefix = "🎁 " + prefix + (scope === undefined ? "" : " " + chalk.cyan(scope));
|
||||||
|
+ let fullPrefix = prefix + (scope === undefined ? "" : " " + chalk.cyan(scope));
|
||||||
|
return fullPrefix + util.format("", ...args).split("\n").reduce((str, line) => {
|
||||||
|
const prefixed = `${str}\n${fullPrefix}`;
|
||||||
|
return line ? `${prefixed} ${line}` : prefixed;
|
||||||
|
@@ -1917,6 +1917,8 @@ let getRollupConfig = (pkg, entrypoints, aliases, type, reportTransformedFile) =
|
||||||
|
external.push(...builtInModules);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ external.push('next', 'react', '@babel/core', 'prettier', '.blitz')
|
||||||
|
+
|
||||||
|
let input = {};
|
||||||
|
entrypoints.forEach(entrypoint => {
|
||||||
|
input[path__default.relative(pkg.directory, path__default.join(entrypoint.directory, "dist", getNameForDistForEntrypoint(entrypoint)))] = entrypoint.source;
|
||||||
4
test/integration/queries/babel.config.js
Normal file
4
test/integration/queries/babel.config.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: ["blitz/babel"],
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
11
test/integration/queries/blitz.config.js
Normal file
11
test/integration/queries/blitz.config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
// replace me
|
||||||
|
async rewrites() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: "/blog/post/:pid",
|
||||||
|
destination: "/blog/:pid",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
16
test/integration/queries/pages/blog/[post].js
Normal file
16
test/integration/queries/pages/blog/[post].js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import {useRouter} from "blitz"
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
const Post = () => {
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div id="as-path">{router.asPath}</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Post.getInitialProps = () => ({hello: "hi"})
|
||||||
|
|
||||||
|
export default Post
|
||||||
3
test/integration/queries/pages/index.js
Normal file
3
test/integration/queries/pages/index.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
const page = () => "hello from sub id"
|
||||||
|
page.getInitialProps = () => ({hello: "hi"})
|
||||||
|
export default page
|
||||||
1
test/integration/queries/pages/normal.js
Normal file
1
test/integration/queries/pages/normal.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default () => <p id="normal-text">a normal page</p>
|
||||||
81
test/integration/queries/test/index.test.ts
Normal file
81
test/integration/queries/test/index.test.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import {
|
||||||
|
blitzBuild,
|
||||||
|
blitzStart,
|
||||||
|
File,
|
||||||
|
findPort,
|
||||||
|
killApp,
|
||||||
|
launchApp,
|
||||||
|
renderViaHTTP,
|
||||||
|
} from "blitz-test-utils"
|
||||||
|
import cheerio from "cheerio"
|
||||||
|
import {join} from "path"
|
||||||
|
|
||||||
|
jest.setTimeout(1000 * 60 * 5)
|
||||||
|
let app: any
|
||||||
|
let appPort: number
|
||||||
|
const appDir = join(__dirname, "..")
|
||||||
|
const blitzConfig = new File(join(appDir, "blitz.config.js"))
|
||||||
|
|
||||||
|
const runTests = () => {
|
||||||
|
it("should have gip in __NEXT_DATA__", async () => {
|
||||||
|
const html = await renderViaHTTP(appPort, "/")
|
||||||
|
const $ = cheerio.load(html)
|
||||||
|
expect(JSON.parse($("#__NEXT_DATA__").text()).gip).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not have gip in __NEXT_DATA__ for non-GIP page", async () => {
|
||||||
|
const html = await renderViaHTTP(appPort, "/normal")
|
||||||
|
const $ = cheerio.load(html)
|
||||||
|
expect("gip" in JSON.parse($("#__NEXT_DATA__").text())).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should have correct router.asPath for direct visit dynamic page", async () => {
|
||||||
|
const html = await renderViaHTTP(appPort, "/blog/1")
|
||||||
|
const $ = cheerio.load(html)
|
||||||
|
expect($("#as-path").text()).toBe("/blog/1")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should have correct router.asPath for direct visit dynamic page rewrite direct", async () => {
|
||||||
|
const html = await renderViaHTTP(appPort, "/blog/post/1")
|
||||||
|
const $ = cheerio.load(html)
|
||||||
|
expect($("#as-path").text()).toBe("/blog/post/1")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("getInitialProps", () => {
|
||||||
|
describe("dev mode", () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
appPort = await findPort()
|
||||||
|
app = await launchApp(appDir, appPort)
|
||||||
|
})
|
||||||
|
afterAll(() => killApp(app))
|
||||||
|
|
||||||
|
runTests()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("serverless mode", () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
blitzConfig.replace("// replace me", `target: 'serverless', `)
|
||||||
|
await blitzBuild(appDir)
|
||||||
|
appPort = await findPort()
|
||||||
|
app = await blitzStart(appDir, appPort)
|
||||||
|
})
|
||||||
|
afterAll(async () => {
|
||||||
|
await killApp(app)
|
||||||
|
blitzConfig.restore()
|
||||||
|
})
|
||||||
|
|
||||||
|
runTests()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("production mode", () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await blitzBuild(appDir)
|
||||||
|
appPort = await findPort()
|
||||||
|
app = await blitzStart(appDir, appPort)
|
||||||
|
})
|
||||||
|
afterAll(() => killApp(app))
|
||||||
|
|
||||||
|
runTests()
|
||||||
|
})
|
||||||
|
})
|
||||||
89
test/jest-environment.js
Normal file
89
test/jest-environment.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// my-custom-environment
|
||||||
|
const http = require("http")
|
||||||
|
const getPort = require("get-port")
|
||||||
|
const seleniumServer = require("selenium-standalone")
|
||||||
|
const NodeEnvironment = require("jest-environment-node")
|
||||||
|
|
||||||
|
const {BROWSER_NAME: browserName = "chrome", SKIP_LOCAL_SELENIUM_SERVER} = process.env
|
||||||
|
|
||||||
|
const newTabPg = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>new tab</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="about:blank" target="_blank" id="new">Click me</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
|
||||||
|
class CustomEnvironment extends NodeEnvironment {
|
||||||
|
async setup() {
|
||||||
|
await super.setup()
|
||||||
|
// Since ie11 doesn't like dataURIs we have to spin up a
|
||||||
|
// server to handle the new tab page
|
||||||
|
this.server = http.createServer((req, res) => {
|
||||||
|
res.statusCode = 200
|
||||||
|
res.end(newTabPg)
|
||||||
|
})
|
||||||
|
const newTabPort = await getPort()
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
this.server.listen(newTabPort, (err) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let seleniumServerPort
|
||||||
|
|
||||||
|
if (browserName !== "chrome" && SKIP_LOCAL_SELENIUM_SERVER !== "true") {
|
||||||
|
console.log("Installing selenium server")
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
seleniumServer.install((err) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log("Starting selenium server")
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
seleniumServer.start((err, child) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
this.seleniumServer = child
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
console.log("Started selenium server")
|
||||||
|
seleniumServerPort = 4444
|
||||||
|
}
|
||||||
|
|
||||||
|
this.global.wd = null
|
||||||
|
this.global._newTabPort = newTabPort
|
||||||
|
this.global.browserName = browserName
|
||||||
|
this.global.seleniumServerPort = seleniumServerPort
|
||||||
|
this.global.browserStackLocalId = global.browserStackLocalId
|
||||||
|
}
|
||||||
|
|
||||||
|
async teardown() {
|
||||||
|
await super.teardown()
|
||||||
|
|
||||||
|
if (this.server) {
|
||||||
|
this.server.close()
|
||||||
|
}
|
||||||
|
if (this.global.wd) {
|
||||||
|
try {
|
||||||
|
await this.global.wd.quit()
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`Failed to quit webdriver instance`, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// must come after wd.quit()
|
||||||
|
if (this.seleniumServer) {
|
||||||
|
this.seleniumServer.kill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CustomEnvironment
|
||||||
24
test/jest-global-setup.js
Normal file
24
test/jest-global-setup.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
let globalSetup = () => {}
|
||||||
|
|
||||||
|
if (process.env.BROWSERSTACK) {
|
||||||
|
const {Local} = require("browserstack-local")
|
||||||
|
const browserStackLocal = new Local()
|
||||||
|
const localBrowserStackOpts = {
|
||||||
|
key: process.env.BROWSERSTACK_ACCESS_KEY,
|
||||||
|
localIdentifier: new Date().getTime(), // Adding a unique local identifier to run parallel tests on BrowserStack
|
||||||
|
}
|
||||||
|
global.browserStackLocal = browserStackLocal
|
||||||
|
global.browserStackLocalId = localBrowserStackOpts.localIdentifier
|
||||||
|
|
||||||
|
globalSetup = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
browserStackLocal.start(localBrowserStackOpts, (err) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
console.log("Started BrowserStackLocal", browserStackLocal.isRunning())
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = globalSetup
|
||||||
9
test/jest-global-teardown.js
Normal file
9
test/jest-global-teardown.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
let globalTeardown = () => {}
|
||||||
|
|
||||||
|
if (process.env.BROWSERSTACK) {
|
||||||
|
globalTeardown = () => global.browserStackLocal.killAllProcesses(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = async () => {
|
||||||
|
await globalTeardown()
|
||||||
|
}
|
||||||
9
test/jest-setup-after-env.js
Normal file
9
test/jest-setup-after-env.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/* eslint-env jest */
|
||||||
|
|
||||||
|
process.env.BLITZ_TEST_ENVIRONMENT = true
|
||||||
|
|
||||||
|
if (process.env.JEST_RETRY_TIMES) {
|
||||||
|
const retries = Number(process.env.JEST_RETRY_TIMES)
|
||||||
|
console.log(`Configuring jest retries: ${retries}`)
|
||||||
|
jest.retryTimes(retries)
|
||||||
|
}
|
||||||
640
test/lib/blitz-test-utils.ts
Normal file
640
test/lib/blitz-test-utils.ts
Normal file
@@ -0,0 +1,640 @@
|
|||||||
|
import {ChildProcess} from "child_process"
|
||||||
|
import spawn from "cross-spawn"
|
||||||
|
import express from "express"
|
||||||
|
import {existsSync, readFileSync, unlinkSync, writeFileSync} from "fs"
|
||||||
|
import {writeFile} from "fs-extra"
|
||||||
|
import getPort from "get-port"
|
||||||
|
import http from "http"
|
||||||
|
// `next` here is the symlink in `test/node_modules/next` which points to the root directory.
|
||||||
|
// This is done so that requiring from `next` works.
|
||||||
|
// The reason we don't import the relative path `../../dist/<etc>` is that it would lead to inconsistent module singletons
|
||||||
|
// import server from "next/dist/server/next"
|
||||||
|
import _pkg from "next/package.json"
|
||||||
|
import fetch from "node-fetch"
|
||||||
|
import path from "path"
|
||||||
|
import qs from "querystring"
|
||||||
|
import treeKill from "tree-kill"
|
||||||
|
|
||||||
|
// export const nextServer = server
|
||||||
|
export const pkg = _pkg
|
||||||
|
|
||||||
|
// polyfill Object.fromEntries for the test/integration/relay-analytics tests
|
||||||
|
// on node 10, this can be removed after we no longer support node 10
|
||||||
|
if (!Object.fromEntries) {
|
||||||
|
Object.fromEntries = require("core-js/features/object/from-entries")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initBlitzServerScript(
|
||||||
|
scriptPath: string,
|
||||||
|
successRegexp: RegExp,
|
||||||
|
env: Record<any, any>,
|
||||||
|
failRegexp: RegExp,
|
||||||
|
opts?: {
|
||||||
|
onStdout?: (stdout: string) => void
|
||||||
|
onStderr?: (stderr: string) => void
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const instance = spawn("node", ["--no-deprecation", scriptPath], {env})
|
||||||
|
|
||||||
|
function handleStdout(data: Buffer) {
|
||||||
|
const message = data.toString()
|
||||||
|
if (successRegexp.test(message)) {
|
||||||
|
resolve(instance)
|
||||||
|
}
|
||||||
|
process.stdout.write(message)
|
||||||
|
|
||||||
|
if (opts && opts.onStdout) {
|
||||||
|
opts.onStdout(message.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStderr(data: Buffer) {
|
||||||
|
const message = data.toString()
|
||||||
|
if (failRegexp && failRegexp.test(message)) {
|
||||||
|
instance.kill()
|
||||||
|
return reject(new Error("received failRegexp"))
|
||||||
|
}
|
||||||
|
process.stderr.write(message)
|
||||||
|
|
||||||
|
if (opts && opts.onStderr) {
|
||||||
|
opts.onStderr(message.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.stdout.on("data", handleStdout)
|
||||||
|
instance.stderr.on("data", handleStderr)
|
||||||
|
|
||||||
|
instance.on("close", () => {
|
||||||
|
instance.stdout.removeListener("data", handleStdout)
|
||||||
|
instance.stderr.removeListener("data", handleStderr)
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.on("error", (err) => {
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderViaAPI(app: any, pathname: string, query: Record<any, any>) {
|
||||||
|
const url = `${pathname}${query ? `?${qs.stringify(query)}` : ""}`
|
||||||
|
return app.renderToHTML({url}, {}, pathname, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function renderViaHTTP(
|
||||||
|
appPort: number,
|
||||||
|
pathname: string,
|
||||||
|
query?: Record<any, any>,
|
||||||
|
opts?: Record<any, any>,
|
||||||
|
) {
|
||||||
|
return fetchViaHTTP(appPort, pathname, query, opts).then((res) => res.text())
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchViaHTTP(
|
||||||
|
appPort: number,
|
||||||
|
pathname: string,
|
||||||
|
query?: Record<any, any>,
|
||||||
|
opts?: Record<any, any>,
|
||||||
|
) {
|
||||||
|
const url = `http://localhost:${appPort}${pathname}${query ? `?${qs.stringify(query)}` : ""}`
|
||||||
|
return fetch(url, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findPort() {
|
||||||
|
return getPort()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RunBlitzCommandOptions {
|
||||||
|
cwd?: string
|
||||||
|
env?: Record<any, any>
|
||||||
|
spawnOptions?: any
|
||||||
|
instance?: any
|
||||||
|
stderr?: boolean
|
||||||
|
stdout?: boolean
|
||||||
|
ignoreFail?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runBlitzCommand(argv: any[], options: RunBlitzCommandOptions = {}) {
|
||||||
|
const blitzDir = path.dirname(require.resolve("blitz/package"))
|
||||||
|
const blitzBin = path.join(blitzDir, "bin/blitz")
|
||||||
|
const cwd = options.cwd || blitzDir
|
||||||
|
// Let Next.js decide the environment
|
||||||
|
const env = {
|
||||||
|
...process.env,
|
||||||
|
...options.env,
|
||||||
|
NODE_ENV: "",
|
||||||
|
__NEXT_TEST_MODE: "true",
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`Running command "blitz ${argv.join(" ")}"`)
|
||||||
|
const instance = spawn("node", ["--no-deprecation", blitzBin, ...argv], {
|
||||||
|
...options.spawnOptions,
|
||||||
|
cwd,
|
||||||
|
env,
|
||||||
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
})
|
||||||
|
|
||||||
|
if (typeof options.instance === "function") {
|
||||||
|
options.instance(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
let stderrOutput = ""
|
||||||
|
if (options.stderr) {
|
||||||
|
instance.stderr.on("data", function (chunk) {
|
||||||
|
stderrOutput += chunk
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let stdoutOutput = ""
|
||||||
|
if (options.stdout) {
|
||||||
|
instance.stdout.on("data", function (chunk) {
|
||||||
|
stdoutOutput += chunk
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.on("close", (code, signal) => {
|
||||||
|
if (!options.stderr && !options.stdout && !options.ignoreFail && code !== 0) {
|
||||||
|
console.log(stderrOutput)
|
||||||
|
return reject(new Error(`command failed with code ${code}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
code,
|
||||||
|
signal,
|
||||||
|
stdout: stdoutOutput,
|
||||||
|
stderr: stderrOutput,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.on("error", (err: any) => {
|
||||||
|
console.log(stderrOutput)
|
||||||
|
err.stdout = stdoutOutput
|
||||||
|
err.stderr = stderrOutput
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RunBlitzLaunchOptions {
|
||||||
|
cwd?: string
|
||||||
|
env?: Record<any, any>
|
||||||
|
onStdout?: (stdout: string) => void
|
||||||
|
onStderr?: (stderr: string) => void
|
||||||
|
stderr?: boolean
|
||||||
|
stdout?: boolean
|
||||||
|
blitzStart?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runBlitzLaunchCommand(
|
||||||
|
argv: any[],
|
||||||
|
stdOut: unknown,
|
||||||
|
opts: RunBlitzLaunchOptions = {},
|
||||||
|
) {
|
||||||
|
const blitzDir = path.dirname(require.resolve("blitz/package"))
|
||||||
|
const blitzBin = path.join(blitzDir, "bin/blitz")
|
||||||
|
const cwd = opts.cwd ?? path.dirname(require.resolve("blitz/package"))
|
||||||
|
console.log(cwd)
|
||||||
|
const env = {
|
||||||
|
...process.env,
|
||||||
|
NODE_ENV: undefined,
|
||||||
|
__NEXT_TEST_MODE: "true",
|
||||||
|
...opts.env,
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<void | string | ChildProcess>((resolve, reject) => {
|
||||||
|
const instance = spawn(
|
||||||
|
"node",
|
||||||
|
["--no-deprecation", blitzBin, opts.blitzStart ? "start" : "dev", ...argv],
|
||||||
|
{cwd, env},
|
||||||
|
)
|
||||||
|
let didResolve = false
|
||||||
|
|
||||||
|
function handleStdout(data: Buffer) {
|
||||||
|
const message = data.toString()
|
||||||
|
const bootupMarkers = {
|
||||||
|
dev: /compiled successfully/i,
|
||||||
|
start: /started server/i,
|
||||||
|
}
|
||||||
|
if (bootupMarkers[opts.blitzStart || stdOut ? "start" : "dev"].test(message)) {
|
||||||
|
if (!didResolve) {
|
||||||
|
didResolve = true
|
||||||
|
resolve(stdOut ? message : instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof opts.onStdout === "function") {
|
||||||
|
opts.onStdout(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.stdout !== false) {
|
||||||
|
process.stdout.write(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStderr(data: Buffer) {
|
||||||
|
const message = data.toString()
|
||||||
|
if (typeof opts.onStderr === "function") {
|
||||||
|
opts.onStderr(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.stderr !== false) {
|
||||||
|
process.stderr.write(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.stdout.on("data", handleStdout)
|
||||||
|
instance.stderr.on("data", handleStderr)
|
||||||
|
|
||||||
|
instance.on("close", () => {
|
||||||
|
instance.stdout.removeListener("data", handleStdout)
|
||||||
|
instance.stderr.removeListener("data", handleStderr)
|
||||||
|
if (!didResolve) {
|
||||||
|
didResolve = true
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.on("error", (err) => {
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch the app in dev mode.
|
||||||
|
export function launchApp(dir: string, port: number, opts: RunBlitzLaunchOptions = {}) {
|
||||||
|
return runBlitzLaunchCommand(["-p", port], undefined, {cwd: dir, ...opts})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function blitzBuild(dir: string, args = [], opts: RunBlitzCommandOptions = {}) {
|
||||||
|
return runBlitzCommand(["build", ...args], {cwd: dir, ...opts})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function blitzExport(dir: string, {outdir}, opts: RunBlitzCommandOptions = {}) {
|
||||||
|
return runBlitzCommand(["export", "--outdir", outdir], {cwd: dir, ...opts})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function blitzExportDefault(dir: string, opts: RunBlitzCommandOptions = {}) {
|
||||||
|
return runBlitzCommand(["export"], {cwd: dir, ...opts})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function blitzStart(dir: string, port: number, opts: RunBlitzLaunchOptions = {}) {
|
||||||
|
return runBlitzLaunchCommand(["-p", port], undefined, {
|
||||||
|
cwd: dir,
|
||||||
|
...opts,
|
||||||
|
blitzStart: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildTS(args = [], cwd: string, env = {}) {
|
||||||
|
cwd = cwd || path.dirname(require.resolve("@blitzjs/cli/package"))
|
||||||
|
env = {...process.env, NODE_ENV: undefined, ...env}
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
const instance = spawn(
|
||||||
|
"node",
|
||||||
|
["--no-deprecation", require.resolve("typescript/lib/tsc"), ...args],
|
||||||
|
{cwd, env},
|
||||||
|
)
|
||||||
|
let output = ""
|
||||||
|
|
||||||
|
const handleData = (chunk) => {
|
||||||
|
output += chunk.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.stdout.on("data", handleData)
|
||||||
|
instance.stderr.on("data", handleData)
|
||||||
|
|
||||||
|
instance.on("exit", (code) => {
|
||||||
|
if (code) {
|
||||||
|
return reject(new Error("exited with code: " + code + "\n" + output))
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill a launched app
|
||||||
|
export async function killApp(instance) {
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
treeKill(instance.pid, (err) => {
|
||||||
|
if (err) {
|
||||||
|
if (
|
||||||
|
process.platform === "win32" &&
|
||||||
|
typeof err.message === "string" &&
|
||||||
|
(err.message.includes(`no running instance of the task`) ||
|
||||||
|
err.message.includes(`not found`))
|
||||||
|
) {
|
||||||
|
// Windows throws an error if the process is already dead
|
||||||
|
//
|
||||||
|
// Command failed: taskkill /pid 6924 /T /F
|
||||||
|
// ERROR: The process with PID 6924 (child process of PID 6736) could not be terminated.
|
||||||
|
// Reason: There is no running instance of the task.
|
||||||
|
return resolve()
|
||||||
|
}
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startApp(app: any) {
|
||||||
|
await app.prepare()
|
||||||
|
const handler = app.getRequestHandler()
|
||||||
|
const server = http.createServer(handler)
|
||||||
|
;(server as any).__app = app
|
||||||
|
|
||||||
|
await promiseCall(server, "listen")
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function stopApp(server: any) {
|
||||||
|
if (server.__app) {
|
||||||
|
await server.__app.close()
|
||||||
|
}
|
||||||
|
await promiseCall(server, "close")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function promiseCall(obj: any, method: any, ...args: any[]) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const newArgs = [
|
||||||
|
...args,
|
||||||
|
function (err: any, res: any) {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
obj[method](...newArgs)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitFor(millis: number) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, millis))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startStaticServer(dir: string) {
|
||||||
|
const app = express()
|
||||||
|
const server = http.createServer(app)
|
||||||
|
app.use(express.static(dir))
|
||||||
|
|
||||||
|
await promiseCall(server, "listen")
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startCleanStaticServer(dir: string) {
|
||||||
|
const app = express()
|
||||||
|
const server = http.createServer(app)
|
||||||
|
app.use(express.static(dir, {extensions: ["html"]}))
|
||||||
|
|
||||||
|
await promiseCall(server, "listen")
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for content in 1 second intervals timing out after
|
||||||
|
// 30 seconds
|
||||||
|
export async function check(contentFn: Function, regex: RegExp, hardError = true) {
|
||||||
|
let content: any
|
||||||
|
let lastErr: any
|
||||||
|
|
||||||
|
for (let tries = 0; tries < 30; tries++) {
|
||||||
|
try {
|
||||||
|
content = await contentFn()
|
||||||
|
if (typeof regex === "string") {
|
||||||
|
if (regex === content) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if (regex.test(content)) {
|
||||||
|
// found the content
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
await waitFor(1000)
|
||||||
|
} catch (err) {
|
||||||
|
await waitFor(1000)
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.error("TIMED OUT CHECK: ", {regex, content, lastErr})
|
||||||
|
|
||||||
|
if (hardError) {
|
||||||
|
throw new Error("TIMED OUT: " + regex + "\n\n" + content)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export class File {
|
||||||
|
path: string
|
||||||
|
originalContent: any
|
||||||
|
constructor(path: string) {
|
||||||
|
this.path = path
|
||||||
|
this.originalContent = existsSync(this.path) ? readFileSync(this.path, "utf8") : null
|
||||||
|
}
|
||||||
|
|
||||||
|
write(content: any) {
|
||||||
|
if (!this.originalContent) {
|
||||||
|
this.originalContent = content
|
||||||
|
}
|
||||||
|
writeFileSync(this.path, content, "utf8")
|
||||||
|
}
|
||||||
|
|
||||||
|
replace(pattern: any, newValue: any) {
|
||||||
|
const currentContent = readFileSync(this.path, "utf8")
|
||||||
|
if (pattern instanceof RegExp) {
|
||||||
|
if (!pattern.test(currentContent)) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to replace content.\n\nPattern: ${pattern.toString()}\n\nContent: ${currentContent}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if (typeof pattern === "string") {
|
||||||
|
if (!currentContent.includes(pattern)) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to replace content.\n\nPattern: ${pattern}\n\nContent: ${currentContent}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unknown replacement attempt type: ${pattern}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const newContent = currentContent.replace(pattern, newValue)
|
||||||
|
this.write(newContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
unlinkSync(this.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
restore() {
|
||||||
|
this.write(this.originalContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function evaluate(browser: any, input: any) {
|
||||||
|
if (typeof input === "function") {
|
||||||
|
const result = await browser.executeScript(input)
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 30))
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
throw new Error(`You must pass a function to be evaluated in the browser.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function retry(fn: Function, duration = 3000, interval = 500, description: string) {
|
||||||
|
if (duration % interval !== 0) {
|
||||||
|
throw new Error(
|
||||||
|
`invalid duration ${duration} and interval ${interval} mix, duration must be evenly divisible by interval`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = duration; i >= 0; i -= interval) {
|
||||||
|
try {
|
||||||
|
return await fn()
|
||||||
|
} catch (err) {
|
||||||
|
if (i === 0) {
|
||||||
|
console.error(`Failed to retry${description ? ` ${description}` : ""} within ${duration}ms`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
console.warn(`Retrying${description ? ` ${description}` : ""} in ${interval}ms`)
|
||||||
|
await waitFor(interval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function hasRedbox(browser: any, expected = true) {
|
||||||
|
let attempts = 30
|
||||||
|
do {
|
||||||
|
const has = await evaluate(browser, () => {
|
||||||
|
return Boolean(
|
||||||
|
[].slice
|
||||||
|
.call(document.querySelectorAll("nextjs-portal"))
|
||||||
|
.find((p: any) =>
|
||||||
|
p.shadowRoot.querySelector(
|
||||||
|
"#nextjs__container_errors_label, #nextjs__container_build_error_label",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
if (has) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (--attempts < 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||||
|
} while (expected)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRedboxHeader(browser: any) {
|
||||||
|
return retry(
|
||||||
|
() =>
|
||||||
|
evaluate(browser, () => {
|
||||||
|
const portal = [].slice
|
||||||
|
.call(document.querySelectorAll("nextjs-portal"))
|
||||||
|
.find((p: any) => p.shadowRoot.querySelector("[data-nextjs-dialog-header"))
|
||||||
|
const root = portal.shadowRoot
|
||||||
|
return root
|
||||||
|
.querySelector("[data-nextjs-dialog-header]")
|
||||||
|
.innerText.replace(/__WEBPACK_DEFAULT_EXPORT__/, "Unknown")
|
||||||
|
}),
|
||||||
|
3000,
|
||||||
|
500,
|
||||||
|
"getRedboxHeader",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRedboxSource(browser: any) {
|
||||||
|
return retry(
|
||||||
|
() =>
|
||||||
|
evaluate(browser, () => {
|
||||||
|
const portal = [].slice
|
||||||
|
.call(document.querySelectorAll("nextjs-portal"))
|
||||||
|
.find((p: any) =>
|
||||||
|
p.shadowRoot.querySelector(
|
||||||
|
"#nextjs__container_errors_label, #nextjs__container_build_error_label",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
const root = portal.shadowRoot
|
||||||
|
return root
|
||||||
|
.querySelector("[data-nextjs-codeframe], [data-nextjs-terminal]")
|
||||||
|
.innerText.replace(/__WEBPACK_DEFAULT_EXPORT__/, "Unknown")
|
||||||
|
}),
|
||||||
|
3000,
|
||||||
|
500,
|
||||||
|
"getRedboxSource",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBrowserBodyText(browser: any) {
|
||||||
|
return browser.eval('document.getElementsByTagName("body")[0].innerText')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeRegEx(src: string) {
|
||||||
|
return new RegExp(src).source.replace(/\^\//g, "^\\/")
|
||||||
|
}
|
||||||
|
|
||||||
|
function readJson(path: string) {
|
||||||
|
return JSON.parse(readFileSync(path) as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBuildManifest(dir: string) {
|
||||||
|
return readJson(path.join(dir, ".next/build-manifest.json"))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPageFileFromBuildManifest(dir: string, page: string) {
|
||||||
|
const buildManifest = getBuildManifest(dir)
|
||||||
|
const pageFiles = buildManifest.pages[page]
|
||||||
|
if (!pageFiles) {
|
||||||
|
throw new Error(`No files for page ${page}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageFile = pageFiles.find(
|
||||||
|
(file: string) =>
|
||||||
|
file.endsWith(".js") && file.includes(`pages${page === "" ? "/index" : page}`),
|
||||||
|
)
|
||||||
|
if (!pageFile) {
|
||||||
|
throw new Error(`No page file for page ${page}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pageFile
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readBlitzBuildClientPageFile(appDir: string, page: string) {
|
||||||
|
const pageFile = getPageFileFromBuildManifest(appDir, page)
|
||||||
|
return readFileSync(path.join(appDir, ".next", pageFile), "utf8")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPagesManifest(dir: string) {
|
||||||
|
const serverFile = path.join(dir, ".next/server/pages-manifest.json")
|
||||||
|
|
||||||
|
if (existsSync(serverFile)) {
|
||||||
|
return readJson(serverFile)
|
||||||
|
}
|
||||||
|
return readJson(path.join(dir, ".next/serverless/pages-manifest.json"))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updatePagesManifest(dir: string, content: any) {
|
||||||
|
const serverFile = path.join(dir, ".next/server/pages-manifest.json")
|
||||||
|
|
||||||
|
if (existsSync(serverFile)) {
|
||||||
|
return writeFile(serverFile, content)
|
||||||
|
}
|
||||||
|
return writeFile(path.join(dir, ".next/serverless/pages-manifest.json"), content)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPageFileFromPagesManifest(dir: string, page: string) {
|
||||||
|
const pagesManifest = getPagesManifest(dir)
|
||||||
|
const pageFile = pagesManifest[page]
|
||||||
|
if (!pageFile) {
|
||||||
|
throw new Error(`No file for page ${page}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pageFile
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readBlitzBuildServerPageFile(appDir: string, page: string) {
|
||||||
|
const pageFile = getPageFileFromPagesManifest(appDir, page)
|
||||||
|
return readFileSync(path.join(appDir, ".next", "server", pageFile), "utf8")
|
||||||
|
}
|
||||||
11
test/tsconfig.json
Normal file
11
test/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
/* "module": "esnext", */
|
||||||
|
/* "target": "esnext", */
|
||||||
|
"allowJs": true,
|
||||||
|
"baseUrl": "./lib",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"noEmit": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"include": ["types/**/*", "packages/**/*", "recipes/**/*"],
|
"include": ["types/**/*", "packages/**/*", "recipes/**/*", "test/**/*"],
|
||||||
"exclude": []
|
"exclude": []
|
||||||
}
|
}
|
||||||
|
|||||||
24
yarn.lock
24
yarn.lock
@@ -3131,10 +3131,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
|
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
|
||||||
integrity sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==
|
integrity sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==
|
||||||
|
|
||||||
"@preconstruct/cli@2.0.5":
|
"@preconstruct/cli@2.0.7":
|
||||||
version "2.0.5"
|
version "2.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@preconstruct/cli/-/cli-2.0.5.tgz#bd952ecae0fbe5cba37040d7f05c41cab3ac4250"
|
resolved "https://registry.yarnpkg.com/@preconstruct/cli/-/cli-2.0.7.tgz#368b0313bc3e04da2442e0133d7bdc3a076a3a55"
|
||||||
integrity sha512-yWB0GwqZi9tTpSmsEkcVYxnieCT89L9938XR7s9ffjKf59GFMwy8O0G8wMA8Rm6jNjf3ob5zuVWvCaoHppUS8Q==
|
integrity sha512-xXKbIZa5k39fLs3ufLo2/PgZjQK/ZBzUeK0nFt+t6xE3i++e6y/RN8GNNzGxOgwgM6+m+OL7rB54ruwB/HVWqw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.5.5"
|
"@babel/code-frame" "^7.5.5"
|
||||||
"@babel/core" "^7.7.7"
|
"@babel/core" "^7.7.7"
|
||||||
@@ -3184,13 +3184,6 @@
|
|||||||
pirates "^4.0.1"
|
pirates "^4.0.1"
|
||||||
source-map-support "^0.5.16"
|
source-map-support "^0.5.16"
|
||||||
|
|
||||||
"@preconstruct/next@2.0.0":
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@preconstruct/next/-/next-2.0.0.tgz#050042c13dde0c671bee0681acb49c31e80ab415"
|
|
||||||
integrity sha512-jpNffjgVKSilBCi3tNs2MEqqGdQBOo5n97B9OCfMDqO9SoiH7MyCmQ+tHCYQvY5gmD6Bf3Fas79N7Rzj6vJBsQ==
|
|
||||||
dependencies:
|
|
||||||
resolve "^1.17.0"
|
|
||||||
|
|
||||||
"@prisma/client@2.19.0":
|
"@prisma/client@2.19.0":
|
||||||
version "2.19.0"
|
version "2.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.19.0.tgz#a45f17a59fd109e95b61bf4b56d4a7642169ec0e"
|
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.19.0.tgz#a45f17a59fd109e95b61bf4b56d4a7642169ec0e"
|
||||||
@@ -3879,6 +3872,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/get-port@4.2.0":
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/get-port/-/get-port-4.2.0.tgz#4fc44616c737d37d3ee7926d86fa975d0afba5e4"
|
||||||
|
integrity sha512-Iv2FAb5RnIk/eFO2CTu8k+0VMmIR15pKbcqRWi+s3ydW+aKXlN2yemP92SrO++ERyJx+p6Ie1ggbLBMbU1SjiQ==
|
||||||
|
dependencies:
|
||||||
|
get-port "*"
|
||||||
|
|
||||||
"@types/glob-stream@*":
|
"@types/glob-stream@*":
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc"
|
resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc"
|
||||||
@@ -10665,7 +10665,7 @@ get-pkg-repo@^1.0.0:
|
|||||||
parse-github-repo-url "^1.3.0"
|
parse-github-repo-url "^1.3.0"
|
||||||
through2 "^2.0.0"
|
through2 "^2.0.0"
|
||||||
|
|
||||||
get-port@5.1.1, get-port@^5.1.1:
|
get-port@*, get-port@5.1.1, get-port@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
|
resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
|
||||||
integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
|
integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
|
||||||
|
|||||||
Reference in New Issue
Block a user