forked from vercel/next.js
/
index.test.js
127 lines (113 loc) · 4.29 KB
/
index.test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* eslint-env jest */
import execa from 'execa'
import fs from 'fs-extra'
import os from 'os'
import path from 'path'
const pnpmExecutable = path.join(
__dirname,
'..',
'..',
'..',
'..',
'node_modules',
'.bin',
'pnpm'
)
const packagesDir = path.join(__dirname, '..', '..', '..', '..', 'packages')
const appDir = path.join(__dirname, '..', 'app')
jest.setTimeout(1000 * 60 * 5)
const runNpm = (cwd, ...args) => execa('npm', [...args], { cwd })
const runPnpm = (cwd, ...args) => execa(pnpmExecutable, [...args], { cwd })
async function usingTempDir(fn) {
const folder = path.join(os.tmpdir(), Math.random().toString(36).substring(2))
await fs.mkdirp(folder)
try {
return await fn(folder)
} finally {
await fs.remove(folder)
}
}
/**
* Using 'npm pack', create a tarball of the given package in
* directory `pkg` and write it to `cwd`.
*
* `pkg` is relative to the monorepo 'packages/' directory.
*
* Return the absolute path to the tarball.
*/
async function pack(cwd, pkg) {
const pkgDir = path.join(packagesDir, pkg)
const { stdout } = await runNpm(
cwd,
'pack',
'--ignore-scripts', // Skip the prepublish script
path.join(packagesDir, pkg)
)
const tarballFilename = stdout.match(/.*\.tgz/)[0]
if (!tarballFilename) {
throw new Error(
`pnpm failed to pack "next" package tarball in directory ${pkgDir}.`
)
}
return path.join(cwd, tarballFilename)
}
describe('pnpm support', () => {
it('should build with dependencies installed via pnpm', async () => {
// Create a Next.js app in a temporary directory, and install dependencies with pnpm.
//
// "next" and its monorepo dependencies are installed by `npm pack`-ing tarballs from
// 'next.js/packages/*', because installing "next" directly via
// `pnpm add path/to/next.js/packages/next` results in a symlink:
// 'app/node_modules/next' -> 'path/to/next.js/packages/next'.
// This is undesired since modules inside "next" would be resolved to the
// next.js monorepo 'node_modules' and lead to false test results;
// installing from a tarball avoids this issue.
//
// The "next" package's monorepo dependencies (e.g. "@next/env", "@next/polyfill-module")
// are not bundled with `npm pack next.js/packages/next`,
// so they need to be packed individually.
// To ensure that they are installed upon installing "next", a package.json "pnpm.overrides"
// field is used to override these dependency paths at install time.
await usingTempDir(async (tempDir) => {
const nextTarballPath = await pack(tempDir, 'next')
const dependencyTarballPaths = {
'@next/env': await pack(tempDir, 'next-env'),
'@next/polyfill-module': await pack(tempDir, 'next-polyfill-module'),
'@next/react-dev-overlay': await pack(tempDir, 'react-dev-overlay'),
'@next/react-refresh-utils': await pack(tempDir, 'react-refresh-utils'),
}
const tempAppDir = path.join(tempDir, 'app')
await fs.copy(appDir, tempAppDir)
// Inject dependency tarball paths into a "pnpm.overrides" field in package.json,
// so that they are installed from packed tarballs rather than from the npm registry.
const packageJsonPath = path.join(tempAppDir, 'package.json')
const overrides = {}
for (const [dependency, tarballPath] of Object.entries(
dependencyTarballPaths
)) {
overrides[dependency] = `file:${tarballPath}`
}
const packageJsonWithOverrides = {
...(await fs.readJson(packageJsonPath)),
pnpm: { overrides },
}
await fs.writeFile(
packageJsonPath,
JSON.stringify(packageJsonWithOverrides, null, 2)
)
await runPnpm(tempAppDir, 'install')
await runPnpm(tempAppDir, 'add', nextTarballPath)
expect(
await fs.pathExists(path.join(tempAppDir, 'pnpm-lock.yaml'))
).toBeTruthy()
const packageJson = await fs.readJson(packageJsonPath)
expect(packageJson.dependencies['next']).toMatch(/^file:/)
for (const dependency of Object.keys(dependencyTarballPaths)) {
expect(packageJson.pnpm.overrides[dependency]).toMatch(/^file:/)
}
const { stdout, stderr } = await runPnpm(tempAppDir, 'run', 'build')
console.log(stdout, stderr)
expect(stdout).toMatch(/Compiled successfully/)
})
})
})