Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a37fb72

Browse files
authoredApr 20, 2023
chore: test reorganization (#2054)
1 parent b341938 commit a37fb72

File tree

15 files changed

+893
-823
lines changed

15 files changed

+893
-823
lines changed
 

‎packages/runtime/src/templates/edge-shared/rsc-data.test.ts

Whitespace-only changes.
Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { extractConfigFromFile } from '../packages/runtime/src/helpers/analysis'
1+
import { extractConfigFromFile } from '../../packages/runtime/src/helpers/analysis'
22
import { resolve } from 'pathe'
3-
import { getDependenciesOfFile } from '../packages/runtime/src/helpers/files'
4-
import { dirname } from 'path'
3+
54
describe('static source analysis', () => {
65
beforeEach(() => {
76
// Spy on console.error
@@ -12,81 +11,72 @@ describe('static source analysis', () => {
1211
;(console.error as jest.Mock).mockRestore()
1312
})
1413
it('should extract config values from a source file', async () => {
15-
const config = await extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/background.js'))
14+
const config = await extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/background.js'))
1615
expect(config).toEqual({
1716
type: 'experimental-background',
1817
})
1918
})
2019
it('should extract config values from a TypeScript source file', async () => {
21-
const config = await extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/background.ts'))
20+
const config = await extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/background.ts'))
2221
expect(config).toEqual({
2322
type: 'experimental-background',
2423
})
2524
})
2625
it('should return an empty config if not defined', async () => {
27-
const config = await extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/missing.ts'))
26+
const config = await extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/missing.ts'))
2827
expect(config).toEqual({})
2928
})
3029

3130
it('should return an empty config if config is invalid', async () => {
32-
const config = await extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/invalid.ts'))
31+
const config = await extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/invalid.ts'))
3332
expect(config).toEqual({})
3433
})
3534

3635
it('should extract schedule values from a source file', async () => {
37-
const config = await extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/scheduled.ts'))
36+
const config = await extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/scheduled.ts'))
3837
expect(config).toEqual({
3938
type: 'experimental-scheduled',
4039
schedule: '@daily',
4140
})
4241
})
4342
it('should throw if schedule is provided when type is background', async () => {
44-
await expect(extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/background-schedule.ts'))).rejects.toThrow(
43+
await expect(extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/background-schedule.ts'))).rejects.toThrow(
4544
'Unsupported config value in test/fixtures/analysis/background-schedule.ts',
4645
)
4746
expect(console.error).toHaveBeenCalledWith(
4847
`Invalid config value in test/fixtures/analysis/background-schedule.ts: schedule is not allowed unless type is "experimental-scheduled"`,
4948
)
5049
})
5150
it('should throw if schedule is provided when type is default', async () => {
52-
await expect(extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/default-schedule.ts'))).rejects.toThrow(
51+
await expect(extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/default-schedule.ts'))).rejects.toThrow(
5352
'Unsupported config value in test/fixtures/analysis/default-schedule.ts',
5453
)
5554
expect(console.error).toHaveBeenCalledWith(
5655
`Invalid config value in test/fixtures/analysis/default-schedule.ts: schedule is not allowed unless type is "experimental-scheduled"`,
5756
)
5857
})
5958
it('should throw if schedule is not provided when type is scheduled', async () => {
60-
await expect(extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/missing-schedule.ts'))).rejects.toThrow(
59+
await expect(extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/missing-schedule.ts'))).rejects.toThrow(
6160
'Unsupported config value in test/fixtures/analysis/missing-schedule.ts',
6261
)
6362
expect(console.error).toHaveBeenCalledWith(
6463
`Invalid config value in test/fixtures/analysis/missing-schedule.ts: schedule is required when type is "experimental-scheduled"`,
6564
)
6665
})
6766
it('should throw if edge runtime is specified for scheduled functions', async () => {
68-
await expect(extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/scheduled-edge.ts'))).rejects.toThrow(
67+
await expect(extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/scheduled-edge.ts'))).rejects.toThrow(
6968
'Unsupported config value in test/fixtures/analysis/scheduled-edge.ts',
7069
)
7170
expect(console.error).toHaveBeenCalledWith(
7271
`Invalid config value in test/fixtures/analysis/scheduled-edge.ts: edge runtime is not supported for scheduled functions`,
7372
)
7473
})
7574
it('should throw if edge runtime is specified for background functions', async () => {
76-
await expect(extractConfigFromFile(resolve(__dirname, 'fixtures/analysis/background-edge.ts'))).rejects.toThrow(
75+
await expect(extractConfigFromFile(resolve(__dirname, '../fixtures/analysis/background-edge.ts'))).rejects.toThrow(
7776
'Unsupported config value in test/fixtures/analysis/background-edge.ts',
7877
)
7978
expect(console.error).toHaveBeenCalledWith(
8079
`Invalid config value in test/fixtures/analysis/background-edge.ts: edge runtime is not supported for background functions`,
8180
)
8281
})
8382
})
84-
85-
describe('dependency tracing', () => {
86-
it('generates dependency list from a source file', async () => {
87-
const dependencies = await getDependenciesOfFile(resolve(__dirname, 'fixtures/analysis/background.js'))
88-
expect(dependencies).toEqual(
89-
['test/webpack-api-runtime.js', 'package.json'].map((dep) => resolve(dirname(__dirname), dep)),
90-
)
91-
})
92-
})

‎test/helpers/config.spec.ts

Lines changed: 429 additions & 0 deletions
Large diffs are not rendered by default.

‎test/edge.spec.ts renamed to ‎test/helpers/edge.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { generateRscDataEdgeManifest } from '../packages/runtime/src/helpers/edge'
1+
import { generateRscDataEdgeManifest } from '../../packages/runtime/src/helpers/edge'
22
import type { PrerenderManifest } from 'next/dist/build'
33

4-
jest.mock('../packages/runtime/src/helpers/functionsMetaData', () => {
5-
const { NEXT_PLUGIN_NAME } = require('../packages/runtime/src/constants')
4+
jest.mock('../../packages/runtime/src/helpers/functionsMetaData', () => {
5+
const { NEXT_PLUGIN_NAME } = require('../../packages/runtime/src/constants')
66
return {
7-
...jest.requireActual('../packages/runtime/src/helpers/functionsMetaData'),
7+
...jest.requireActual('../../packages/runtime/src/helpers/functionsMetaData'),
88
getPluginVersion: async () => `${NEXT_PLUGIN_NAME}@1.0.0`,
99
}
1010
})

‎test/helpers/files.spec.ts

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import {
2+
matchMiddleware,
3+
stripLocale,
4+
matchesRedirect,
5+
matchesRewrite,
6+
patchNextFiles,
7+
unpatchNextFiles,
8+
getDependenciesOfFile,
9+
} from "../../packages/runtime/src/helpers/files"
10+
import {
11+
readFileSync,
12+
copy,
13+
ensureDir,
14+
} from "fs-extra"
15+
import path from "path"
16+
import { dirname } from "path"
17+
import { resolve } from 'pathe'
18+
import { join } from "pathe"
19+
import { Rewrites } from "../../packages/runtime/src/helpers/types"
20+
import { describeCwdTmpDir, moveNextDist } from "../test-utils"
21+
22+
const REDIRECTS: Rewrites = [
23+
{
24+
source: '/:file((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/]+\\.\\w+)/',
25+
destination: '/:file',
26+
locale: false,
27+
internal: true,
28+
statusCode: 308,
29+
regex: '^(?:/((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/]+\\.\\w+))/$',
30+
},
31+
{
32+
source: '/:notfile((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/\\.]+)',
33+
destination: '/:notfile/',
34+
locale: false,
35+
internal: true,
36+
statusCode: 308,
37+
regex: '^(?:/((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/\\.]+))$',
38+
},
39+
{
40+
source: '/en/redirectme',
41+
destination: '/',
42+
statusCode: 308,
43+
regex: '^(?!/_next)/en/redirectme(?:/)?$',
44+
},
45+
{
46+
source: '/:nextInternalLocale(en|es|fr)/redirectme',
47+
destination: '/:nextInternalLocale/',
48+
statusCode: 308,
49+
regex: '^(?!/_next)(?:/(en|es|fr))/redirectme(?:/)?$',
50+
},
51+
]
52+
53+
const REWRITES: Rewrites = [
54+
{
55+
source: '/:nextInternalLocale(en|es|fr)/old/:path*',
56+
destination: '/:nextInternalLocale/:path*',
57+
regex: '^(?:/(en|es|fr))/old(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$',
58+
statusCode: 308,
59+
},
60+
]
61+
62+
describe('files utility functions', () => {
63+
test('middleware tester matches correct paths', () => {
64+
const middleware = ['middle', 'sub/directory']
65+
const paths = [
66+
'middle.html',
67+
'middle',
68+
'middle/',
69+
'middle/ware',
70+
'sub/directory',
71+
'sub/directory.html',
72+
'sub/directory/child',
73+
'sub/directory/child.html',
74+
]
75+
for (const path of paths) {
76+
expect(matchMiddleware(middleware, path)).toBeTruthy()
77+
}
78+
})
79+
80+
test('middleware tester does not match incorrect paths', () => {
81+
const middleware = ['middle', 'sub/directory']
82+
const paths = [
83+
'middl',
84+
'',
85+
'somethingelse',
86+
'another.html',
87+
'another/middle.html',
88+
'sub/anotherdirectory.html',
89+
'sub/directoryelse',
90+
'sub/directoryelse.html',
91+
]
92+
for (const path of paths) {
93+
expect(matchMiddleware(middleware, path)).toBeFalsy()
94+
}
95+
})
96+
97+
test('middleware tester matches root middleware', () => {
98+
const middleware = ['']
99+
const paths = [
100+
'middl',
101+
'',
102+
'somethingelse',
103+
'another.html',
104+
'another/middle.html',
105+
'sub/anotherdirectory.html',
106+
'sub/directoryelse',
107+
'sub/directoryelse.html',
108+
]
109+
for (const path of paths) {
110+
expect(matchMiddleware(middleware, path)).toBeTruthy()
111+
}
112+
})
113+
114+
test('middleware tester matches root middleware', () => {
115+
const paths = [
116+
'middl',
117+
'',
118+
'somethingelse',
119+
'another.html',
120+
'another/middle.html',
121+
'sub/anotherdirectory.html',
122+
'sub/directoryelse',
123+
'sub/directoryelse.html',
124+
]
125+
for (const path of paths) {
126+
expect(matchMiddleware(undefined, path)).toBeFalsy()
127+
}
128+
})
129+
130+
test('stripLocale correctly strips matching locales', () => {
131+
const locales = ['en', 'fr', 'en-GB']
132+
const paths = [
133+
['en/file.html', 'file.html'],
134+
['fr/file.html', 'file.html'],
135+
['en-GB/file.html', 'file.html'],
136+
['file.html', 'file.html'],
137+
]
138+
139+
for (const [path, expected] of paths) {
140+
expect(stripLocale(path, locales)).toEqual(expected)
141+
}
142+
})
143+
144+
test('stripLocale does not touch non-matching matching locales', () => {
145+
const locales = ['en', 'fr', 'en-GB']
146+
const paths = ['de/file.html', 'enfile.html', 'en-US/file.html']
147+
for (const path of paths) {
148+
expect(stripLocale(path, locales)).toEqual(path)
149+
}
150+
})
151+
152+
test('matchesRedirect correctly matches paths with locales', () => {
153+
const paths = ['en/redirectme.html', 'en/redirectme.json', 'fr/redirectme.html', 'fr/redirectme.json']
154+
paths.forEach((path) => {
155+
expect(matchesRedirect(path, REDIRECTS)).toBeTruthy()
156+
})
157+
})
158+
159+
test("matchesRedirect doesn't match paths with invalid locales", () => {
160+
const paths = ['dk/redirectme.html', 'dk/redirectme.json', 'gr/redirectme.html', 'gr/redirectme.json']
161+
paths.forEach((path) => {
162+
expect(matchesRedirect(path, REDIRECTS)).toBeFalsy()
163+
})
164+
})
165+
166+
test("matchesRedirect doesn't match internal redirects", () => {
167+
const paths = ['en/notrailingslash']
168+
paths.forEach((path) => {
169+
expect(matchesRedirect(path, REDIRECTS)).toBeFalsy()
170+
})
171+
})
172+
173+
it('matchesRewrite matches array of rewrites', () => {
174+
expect(matchesRewrite('en/old/page.html', REWRITES)).toBeTruthy()
175+
})
176+
177+
it('matchesRewrite matches beforeFiles rewrites', () => {
178+
expect(matchesRewrite('en/old/page.html', { beforeFiles: REWRITES })).toBeTruthy()
179+
})
180+
181+
it("matchesRewrite doesn't match afterFiles rewrites", () => {
182+
expect(matchesRewrite('en/old/page.html', { afterFiles: REWRITES })).toBeFalsy()
183+
})
184+
185+
it('matchesRewrite matches various paths', () => {
186+
const paths = ['en/old/page.html', 'fr/old/page.html', 'en/old/deep/page.html', 'en/old.html']
187+
paths.forEach((path) => {
188+
expect(matchesRewrite(path, REWRITES)).toBeTruthy()
189+
})
190+
})
191+
})
192+
193+
describeCwdTmpDir('file patching', () => {
194+
it('patches Next server files', async () => {
195+
const root = path.resolve(dirname(resolve(__dirname, '..')))
196+
await copy(join(root, 'package.json'), path.join(process.cwd(), 'package.json'))
197+
await ensureDir(path.join(process.cwd(), 'node_modules'))
198+
await copy(path.join(root, 'node_modules', 'next'), path.join(process.cwd(), 'node_modules', 'next'))
199+
200+
await patchNextFiles(process.cwd())
201+
const serverFile = path.resolve(process.cwd(), 'node_modules', 'next', 'dist', 'server', 'base-server.js')
202+
const patchedData = await readFileSync(serverFile, 'utf8')
203+
expect(patchedData.includes('_REVALIDATE_SSG')).toBeTruthy()
204+
expect(patchedData.includes('private: isPreviewMode && cachedData')).toBeTruthy()
205+
206+
await unpatchNextFiles(process.cwd())
207+
208+
const unPatchedData = await readFileSync(serverFile, 'utf8')
209+
expect(unPatchedData.includes('_REVALIDATE_SSG')).toBeFalsy()
210+
expect(unPatchedData.includes('private: isPreviewMode && cachedData')).toBeFalsy()
211+
})
212+
})
213+
214+
describe('dependency tracing', () => {
215+
it('generates dependency list from a source file', async () => {
216+
const dependencies = await getDependenciesOfFile(resolve(__dirname, '../fixtures/analysis/background.js'))
217+
expect(dependencies).toEqual(
218+
['test/webpack-api-runtime.js', 'package.json'].map((dep) => resolve(dirname(resolve(__dirname, '..')), dep)),
219+
)
220+
})
221+
})

‎test/helpers/functions.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { getExtendedApiRouteConfigs } from "../../packages/runtime/src/helpers/functions"
2+
import { describeCwdTmpDir, moveNextDist } from "../test-utils"
3+
4+
describeCwdTmpDir('api route file analysis', () => {
5+
it('extracts correct route configs from source files', async () => {
6+
await moveNextDist()
7+
const configs = await getExtendedApiRouteConfigs('.next', process.cwd())
8+
// Using a Set means the order doesn't matter
9+
expect(new Set(configs)).toEqual(
10+
new Set([
11+
{
12+
compiled: 'pages/api/hello-background.js',
13+
config: { type: 'experimental-background' },
14+
route: '/api/hello-background',
15+
},
16+
{
17+
compiled: 'pages/api/hello-scheduled.js',
18+
config: { schedule: '@hourly', type: 'experimental-scheduled' },
19+
route: '/api/hello-scheduled',
20+
},
21+
]),
22+
)
23+
})
24+
})

‎test/functionsMetaData.spec.ts renamed to ‎test/helpers/functionsMetaData.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { readJSON } from 'fs-extra'
22
import mock from 'mock-fs'
33
import { join } from 'pathe'
4-
import { NEXT_PLUGIN_NAME } from '../packages/runtime/src/constants'
5-
import { writeFunctionConfiguration } from '../packages/runtime/src/helpers/functionsMetaData'
4+
import { NEXT_PLUGIN_NAME } from '../../packages/runtime/src/constants'
5+
import { writeFunctionConfiguration } from '../../packages/runtime/src/helpers/functionsMetaData'
66

77
describe('writeFunctionConfiguration', () => {
88
afterEach(() => {

‎test/matchers.spec.ts renamed to ‎test/helpers/matchers.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { makeLocaleOptional, stripLookahead } from '../packages/runtime/src/helpers/matchers'
2-
import { getEdgeFunctionPatternForPage } from '../packages/runtime/src/helpers/edge'
1+
import { makeLocaleOptional, stripLookahead } from '../../packages/runtime/src/helpers/matchers'
2+
import { getEdgeFunctionPatternForPage } from '../../packages/runtime/src/helpers/edge'
33
const makeDataPath = (path: string) => `/_next/data/build-id${path === '/' ? '/index' : path}.json`
44

55
function checkPath(path: string, regex: string) {

‎test/helpers/verification.spec.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import Chance from 'chance'
2-
import { checkNextSiteHasBuilt, checkZipSize } from '../../packages/runtime/src/helpers/verification'
2+
import { checkNextSiteHasBuilt, checkZipSize, getProblematicUserRewrites } from '../../packages/runtime/src/helpers/verification'
33
import { outdent } from 'outdent'
4+
import type { NetlifyPluginOptions } from '@netlify/build'
5+
import { moveNextDist } from "../test-utils"
6+
7+
const netlifyConfig = { build: { command: 'npm run build' }, functions: {}, redirects: [], headers: [] } as NetlifyPluginOptions["netlifyConfig"]
48

59
import type { NetlifyPluginUtils } from '@netlify/build'
610
type FailBuild = NetlifyPluginUtils['build']['failBuild']
@@ -100,3 +104,32 @@ describe('checkZipSize', () => {
100104
expect(consoleSpy).toHaveBeenCalledWith('Function bundle size check was DISABLED with the DISABLE_BUNDLE_ZIP_SIZE_CHECK environment variable. Your deployment will break if it exceeds the maximum supported size of function zip files in your account.')
101105
})
102106
})
107+
108+
describe("getProblematicUserRewrites", () => {
109+
it('finds problematic user rewrites', async () => {
110+
await moveNextDist()
111+
const rewrites = getProblematicUserRewrites({
112+
redirects: [
113+
{ from: '/previous', to: '/rewrites-are-a-problem', status: 200 },
114+
{ from: '/api', to: '/.netlify/functions/are-ok', status: 200 },
115+
{ from: '/remote', to: 'http://example.com/proxying/is/ok', status: 200 },
116+
{ from: '/old', to: '/redirects-are-fine' },
117+
{ from: '/*', to: '/404-is-a-problem', status: 404 },
118+
...netlifyConfig.redirects,
119+
],
120+
basePath: '',
121+
})
122+
expect(rewrites).toEqual([
123+
{
124+
from: '/previous',
125+
status: 200,
126+
to: '/rewrites-are-a-problem',
127+
},
128+
{
129+
from: '/*',
130+
status: 404,
131+
to: '/404-is-a-problem',
132+
},
133+
])
134+
})
135+
})

‎test/index.spec.js renamed to ‎test/index.spec.ts

Lines changed: 21 additions & 786 deletions
Large diffs are not rendered by default.

‎test/rsc-data.spec.ts renamed to ‎test/templates/edge-shared/rsc-data.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getRscDataRouter, PrerenderManifest } from '../packages/runtime/src/templates/edge-shared/rsc-data'
1+
import { getRscDataRouter, PrerenderManifest } from '../../../packages/runtime/src/templates/edge-shared/rsc-data'
22

33
const basePrerenderManifest: PrerenderManifest = {
44
version: 3,

‎test/handlerUtils.spec.ts renamed to ‎test/templates/handlerUtils.spec.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,17 @@ import {
33
unlocalizeRoute,
44
localizeRoute,
55
localizeDataRoute,
6-
} from '../packages/runtime/src/templates/handlerUtils'
6+
downloadFile,
7+
} from '../../packages/runtime/src/templates/handlerUtils'
8+
import { join } from "pathe"
9+
import os from "os"
10+
import path from "path"
11+
import {
12+
unlink,
13+
existsSync,
14+
readFileSync,
15+
ensureDir,
16+
} from "fs-extra"
717

818
describe('normalizeRoute', () => {
919
it('removes a trailing slash from a route', () => {
@@ -85,3 +95,37 @@ describe('localizeDataRoute', () => {
8595
expect(localizeDataRoute('/foo.rsc', '/foo')).toEqual('/foo.rsc')
8696
})
8797
})
98+
99+
describe('downloadFile', () => {
100+
it('can download a file', async () => {
101+
const url =
102+
'https://raw.githubusercontent.com/netlify/next-runtime/c2668af24a78eb69b33222913f44c1900a3bce23/manifest.yml'
103+
const tmpFile = join(os.tmpdir(), 'next-test', 'downloadfile.txt')
104+
await ensureDir(path.dirname(tmpFile))
105+
await downloadFile(url, tmpFile)
106+
expect(existsSync(tmpFile)).toBeTruthy()
107+
expect(readFileSync(tmpFile, 'utf8')).toMatchInlineSnapshot(`
108+
"name: netlify-plugin-nextjs-experimental
109+
"
110+
`)
111+
await unlink(tmpFile)
112+
})
113+
114+
it('throws on bad domain', async () => {
115+
const url = 'https://nonexistentdomain.example'
116+
const tmpFile = join(os.tmpdir(), 'next-test', 'downloadfile.txt')
117+
await ensureDir(path.dirname(tmpFile))
118+
await expect(downloadFile(url, tmpFile)).rejects.toThrowErrorMatchingInlineSnapshot(
119+
`"getaddrinfo ENOTFOUND nonexistentdomain.example"`,
120+
)
121+
})
122+
123+
it('throws on 404', async () => {
124+
const url = 'https://example.com/nonexistentfile'
125+
const tmpFile = join(os.tmpdir(), 'next-test', 'downloadfile.txt')
126+
await ensureDir(path.dirname(tmpFile))
127+
await expect(downloadFile(url, tmpFile)).rejects.toThrowError(
128+
'Failed to download https://example.com/nonexistentfile: 404 Not Found',
129+
)
130+
})
131+
})

‎test/server.spec.ts renamed to ‎test/templates/server.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { mockRequest } from 'next/dist/server/lib/mock-request'
22
import { Options } from 'next/dist/server/next-server'
33

4-
import { getNextServer, NextServerType, netlifyApiFetch } from '../packages/runtime/src/templates/handlerUtils'
5-
import { NetlifyNextServer, NetlifyConfig } from '../packages/runtime/src/templates/server'
4+
import { getNextServer, NextServerType, netlifyApiFetch } from '../../packages/runtime/src/templates/handlerUtils'
5+
import { NetlifyNextServer, NetlifyConfig } from '../../packages/runtime/src/templates/server'
66

7-
jest.mock('../packages/runtime/src/templates/handlerUtils', () => {
8-
const originalModule = jest.requireActual('../packages/runtime/src/templates/handlerUtils')
7+
jest.mock('../../packages/runtime/src/templates/handlerUtils', () => {
8+
const originalModule = jest.requireActual('../../packages/runtime/src/templates/handlerUtils')
99

1010
return {
1111
__esModule: true,

‎test/test-utils.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import path from "path"
2+
import { dirname } from "path"
3+
import cpy from "cpy"
4+
import {
5+
writeJSON,
6+
existsSync,
7+
ensureDir,
8+
readJson,
9+
copy,
10+
} from "fs-extra"
11+
import { dir as getTmpDir } from "tmp-promise"
12+
13+
const FIXTURES_DIR = `${__dirname}/fixtures`
14+
const SAMPLE_PROJECT_DIR = `${__dirname}/../demos/default`
15+
16+
// Temporary switch cwd
17+
export const changeCwd = function (cwd) {
18+
const originalCwd = process.cwd()
19+
process.chdir(cwd)
20+
return () => {
21+
process.chdir(originalCwd)
22+
}
23+
}
24+
25+
const rewriteAppDir = async function (dir = '.next') {
26+
const manifest = path.join(dir, 'required-server-files.json')
27+
const manifestContent = await readJson(manifest)
28+
manifestContent.appDir = process.cwd()
29+
30+
await writeJSON(manifest, manifestContent)
31+
}
32+
33+
// Move .next from sample project to current directory
34+
export const moveNextDist = async function (dir = '.next', copyMods = false) {
35+
if (copyMods) {
36+
await copyModules(['next', 'sharp'])
37+
} else {
38+
await stubModules(['next', 'sharp'])
39+
}
40+
await ensureDir(dirname(dir))
41+
await copy(path.join(SAMPLE_PROJECT_DIR, '.next'), path.join(process.cwd(), dir))
42+
43+
for (const file of ['pages', 'app', 'src', 'components', 'public', 'components', 'hello.txt', 'package.json']) {
44+
const source = path.join(SAMPLE_PROJECT_DIR, file)
45+
if (existsSync(source)) {
46+
await copy(source, path.join(process.cwd(), file))
47+
}
48+
}
49+
50+
await rewriteAppDir(dir)
51+
}
52+
53+
export const copyModules = async function (modules) {
54+
for (const mod of modules) {
55+
const source = dirname(require.resolve(`${mod}/package.json`))
56+
const dest = path.join(process.cwd(), 'node_modules', mod)
57+
await copy(source, dest)
58+
}
59+
}
60+
61+
export const stubModules = async function (modules) {
62+
for (const mod of modules) {
63+
const dir = path.join(process.cwd(), 'node_modules', mod)
64+
await ensureDir(dir)
65+
await writeJSON(path.join(dir, 'package.json'), { name: mod })
66+
}
67+
}
68+
69+
// Copy fixture files to the current directory
70+
export const useFixture = async function (fixtureName) {
71+
const fixtureDir = `${FIXTURES_DIR}/${fixtureName}`
72+
await cpy('**', process.cwd(), { cwd: fixtureDir, parents: true, overwrite: true, dot: true })
73+
}
74+
75+
// Change current cwd() to a temporary directory
76+
export const describeCwdTmpDir = (name: string, fn: () => void): void => {
77+
describe(name, () => {
78+
let restoreCwd
79+
let cleanup
80+
81+
beforeEach(async () => {
82+
const tmpDir = await getTmpDir({ unsafeCleanup: true })
83+
restoreCwd = changeCwd(tmpDir.path)
84+
cleanup = tmpDir.cleanup
85+
})
86+
87+
afterEach(async () => {
88+
restoreCwd()
89+
await cleanup()
90+
})
91+
92+
fn()
93+
})
94+
}

0 commit comments

Comments
 (0)
Please sign in to comment.