Skip to content

Commit

Permalink
test: enable integration tests for framework detection again (#5940)
Browse files Browse the repository at this point in the history
* test: enable integration tests for framework detection again

* chore: disable function server logging by default
  • Loading branch information
lukasholzer authored Aug 11, 2023
1 parent 7382dfb commit b381412
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 173 deletions.
31 changes: 26 additions & 5 deletions src/lib/functions/server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,20 @@ const getFunctionsServer = (options) => {
return app
}

/**
*
* @param {object} options
* @param {import('../../commands/base-command.mjs').default} options.command
* @param {*} options.capabilities
* @param {*} options.config
* @param {boolean} options.debug
* @param {*} options.loadDistFunctions
* @param {*} options.settings
* @param {*} options.site
* @param {string} options.siteUrl
* @param {*} options.timeouts
* @returns
*/
export const startFunctionsServer = async (options) => {
const { capabilities, command, config, debug, loadDistFunctions, settings, site, siteUrl, timeouts } = options
const internalFunctionsDir = await getInternalFunctionsDir({ base: site.root })
Expand Down Expand Up @@ -260,15 +274,22 @@ export const startFunctionsServer = async (options) => {

const server = await getFunctionsServer(Object.assign(options, { functionsRegistry }))

await startWebServer({ server, settings })
await startWebServer({ server, settings, debug })
}

const startWebServer = async ({ server, settings }) => {
await new Promise((resolve) => {
server.listen(settings.functionsPort, (err) => {
/**
*
* @param {object} config
* @param {boolean} config.debug
* @param {ReturnType<Awaited<typeof getFunctionsServer>>} config.server
* @param {*} config.settings
*/
const startWebServer = async ({ debug, server, settings }) => {
await new Promise((/** @type {(resolve: void) => void} */ resolve) => {
server.listen(settings.functionsPort, (/** @type {unknown} */ err) => {
if (err) {
errorExit(`${NETLIFYDEVERR} Unable to start functions server: ${err}`)
} else {
} else if (debug) {
log(`${NETLIFYDEVLOG} Functions server is listening on ${settings.functionsPort}`)
}
resolve()
Expand Down
297 changes: 148 additions & 149 deletions tests/integration/600.framework-detection.test.cjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// eslint-disable-next-line ava/use-test
const avaTest = require('ava')
const { isCI } = require('ci-info')
// const execa = require('execa')
const execa = require('execa')

// const cliPath = require('./utils/cli-path.cjs')
// const { getExecaOptions, withDevServer } = require('./utils/dev-server.cjs')
const { withDevServer } = require('./utils/dev-server.cjs')
const cliPath = require('./utils/cli-path.cjs')
const { getExecaOptions, withDevServer } = require('./utils/dev-server.cjs')
const got = require('./utils/got.cjs')
// const { DOWN, answerWithValue, handleQuestions } = require('./utils/handle-questions.cjs')
const { DOWN, answerWithValue, handleQuestions } = require('./utils/handle-questions.cjs')
const { withSiteBuilder } = require('./utils/site-builder.cjs')
const { normalize } = require('./utils/snapshots.cjs')

Expand Down Expand Up @@ -223,147 +222,147 @@ test(`should print specific error when command doesn't exist`, async (t) => {
})
})

// test.skip('should prompt when multiple frameworks are detected', async (t) => {
// await withSiteBuilder('site-with-multiple-frameworks', async (builder) => {
// await builder
// .withPackageJson({
// packageJson: {
// dependencies: { 'react-scripts': '1.0.0', gatsby: '^3.0.0' },
// scripts: { start: 'react-scripts start', develop: 'gatsby develop' },
// },
// })
// .withContentFile({ path: 'gatsby-config.js', content: '' })
// .buildAsync()

// // a failure is expected since this is not a true framework project
// const error = await t.throwsAsync(async () => {
// const childProcess = execa(cliPath, ['dev', '--offline'], getExecaOptions({ cwd: builder.directory }))

// handleQuestions(childProcess, [
// {
// question: 'Multiple possible start commands found',
// answer: answerWithValue(DOWN),
// },
// ])

// await childProcess
// })
// t.snapshot(normalize(error.stdout, { duration: true, filePath: true }))
// })
// })

// test.skip('should not run framework detection if command and targetPort are configured', async (t) => {
// await withSiteBuilder('site-with-hugo-config', async (builder) => {
// await builder.withContentFile({ path: 'config.toml', content: '' }).buildAsync()

// // a failure is expected since the command exits early
// const error = await t.throwsAsync(() =>
// withDevServer(
// { cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', '3000'] },
// () => {},
// true,
// ),
// )
// t.snapshot(normalize(error.stdout, { duration: true, filePath: true }))
// })
// })

// test.skip('should filter frameworks with no dev command', async (t) => {
// await withSiteBuilder('site-with-gulp', async (builder) => {
// await builder
// .withContentFile({
// path: 'index.html',
// content,
// })
// .withPackageJson({
// packageJson: { dependencies: { gulp: '1.0.0' } },
// })
// .buildAsync()

// await withDevServer({ cwd: builder.directory }, async ({ output, url }) => {
// const response = await got(url).text()
// t.is(response, content)

// t.snapshot(normalize(output, { duration: true, filePath: true }))
// })
// })
// })

// test.skip('should start static service for frameworks without port, forced framework', async (t) => {
// await withSiteBuilder('site-with-remix', async (builder) => {
// await builder.withNetlifyToml({ config: { dev: { framework: 'remix' } } }).buildAsync()

// // a failure is expected since this is not a true remix project
// const error = await t.throwsAsync(() => withDevServer({ cwd: builder.directory }, () => {}, true))
// t.true(error.stdout.includes(`Failed running command: remix watch. Please verify 'remix' exists`))
// })
// })

// test.skip('should start static service for frameworks without port, detected framework', async (t) => {
// await withSiteBuilder('site-with-remix', async (builder) => {
// await builder
// .withPackageJson({
// packageJson: {
// dependencies: { remix: '^1.0.0', '@remix-run/netlify': '^1.0.0' },
// scripts: {},
// },
// })
// .withContentFile({ path: 'remix.config.js', content: '' })
// .buildAsync()

// // a failure is expected since this is not a true remix project
// const error = await t.throwsAsync(() => withDevServer({ cwd: builder.directory }, () => {}, true))
// t.true(error.stdout.includes(`Failed running command: remix watch. Please verify 'remix' exists`))
// })
// })

// test.skip('should run and serve a production build when using the `serve` command', async (t) => {
// await withSiteBuilder('site-with-framework', async (builder) => {
// await builder
// .withNetlifyToml({
// config: {
// build: { publish: 'public' },
// context: {
// dev: { environment: { CONTEXT_CHECK: 'DEV' } },
// production: { environment: { CONTEXT_CHECK: 'PRODUCTION' } },
// },
// functions: { directory: 'functions' },
// plugins: [{ package: './plugins/frameworker' }],
// },
// })
// .withBuildPlugin({
// name: 'frameworker',
// plugin: {
// onPreBuild: async ({ netlifyConfig }) => {
// // eslint-disable-next-line n/global-require
// const { mkdir, writeFile } = require('fs').promises

// const generatedFunctionsDir = 'new_functions'
// netlifyConfig.functions.directory = generatedFunctionsDir

// netlifyConfig.redirects.push({
// from: '/hello',
// to: '/.netlify/functions/hello',
// })

// await mkdir(generatedFunctionsDir)
// await writeFile(
// `${generatedFunctionsDir}/hello.js`,
// `const { CONTEXT_CHECK, NETLIFY_DEV } = process.env; exports.handler = async () => ({ statusCode: 200, body: JSON.stringify({ CONTEXT_CHECK, NETLIFY_DEV }) })`,
// )
// },
// },
// })
// .buildAsync()

// await withDevServer(
// { cwd: builder.directory, context: null, debug: true, serve: true },
// async ({ output, url }) => {
// const response = await got(`${url}/hello`).json()
// t.deepEqual(response, { CONTEXT_CHECK: 'PRODUCTION' })

// t.snapshot(normalize(output, { duration: true, filePath: true }))
// },
// )
// })
// })
test('should prompt when multiple frameworks are detected', async (t) => {
await withSiteBuilder('site-with-multiple-frameworks', async (builder) => {
await builder
.withPackageJson({
packageJson: {
dependencies: { 'react-scripts': '1.0.0', gatsby: '^3.0.0' },
scripts: { start: 'react-scripts start', develop: 'gatsby develop' },
},
})
.withContentFile({ path: 'gatsby-config.js', content: '' })
.buildAsync()

// a failure is expected since this is not a true framework project
const error = await t.throwsAsync(async () => {
const childProcess = execa(cliPath, ['dev', '--offline'], getExecaOptions({ cwd: builder.directory }))

handleQuestions(childProcess, [
{
question: 'Multiple possible dev commands found',
answer: answerWithValue(DOWN),
},
])

await childProcess
})
t.snapshot(normalize(error.stdout, { duration: true, filePath: true }))
})
})

test('should not run framework detection if command and targetPort are configured', async (t) => {
await withSiteBuilder('site-with-hugo-config', async (builder) => {
await builder.withContentFile({ path: 'config.toml', content: '' }).buildAsync()

// a failure is expected since the command exits early
const error = await t.throwsAsync(() =>
withDevServer(
{ cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', '3000'] },
() => {},
true,
),
)
t.snapshot(normalize(error.stdout, { duration: true, filePath: true }))
})
})

test('should filter frameworks with no dev command', async (t) => {
await withSiteBuilder('site-with-gulp', async (builder) => {
await builder
.withContentFile({
path: 'index.html',
content,
})
.withPackageJson({
packageJson: { dependencies: { gulp: '1.0.0' } },
})
.buildAsync()

await withDevServer({ cwd: builder.directory }, async ({ output, url }) => {
const response = await got(url).text()
t.is(response, content)

t.snapshot(normalize(output, { duration: true, filePath: true }))
})
})
})

test('should start static service for frameworks without port, forced framework', async (t) => {
await withSiteBuilder('site-with-remix', async (builder) => {
await builder.withNetlifyToml({ config: { dev: { framework: 'remix' } } }).buildAsync()

// a failure is expected since this is not a true remix project
const error = await t.throwsAsync(() => withDevServer({ cwd: builder.directory }, () => {}, true))
t.true(error.stdout.includes(`Failed running command: remix watch. Please verify 'remix' exists`))
})
})

test('should start static service for frameworks without port, detected framework', async (t) => {
await withSiteBuilder('site-with-remix', async (builder) => {
await builder
.withPackageJson({
packageJson: {
dependencies: { remix: '^1.0.0', '@remix-run/netlify': '^1.0.0' },
scripts: {},
},
})
.withContentFile({ path: 'remix.config.js', content: '' })
.buildAsync()

// a failure is expected since this is not a true remix project
const error = await t.throwsAsync(() => withDevServer({ cwd: builder.directory }, () => {}, true))
t.true(error.stdout.includes(`Failed running command: remix watch. Please verify 'remix' exists`))
})
})

test('should run and serve a production build when using the `serve` command', async (t) => {
await withSiteBuilder('site-with-framework', async (builder) => {
await builder
.withNetlifyToml({
config: {
build: { publish: 'public' },
context: {
dev: { environment: { CONTEXT_CHECK: 'DEV' } },
production: { environment: { CONTEXT_CHECK: 'PRODUCTION' } },
},
functions: { directory: 'functions' },
plugins: [{ package: './plugins/frameworker' }],
},
})
.withBuildPlugin({
name: 'frameworker',
plugin: {
onPreBuild: async ({ netlifyConfig }) => {
// eslint-disable-next-line n/global-require
const { mkdir, writeFile } = require('fs').promises

const generatedFunctionsDir = 'new_functions'
netlifyConfig.functions.directory = generatedFunctionsDir

netlifyConfig.redirects.push({
from: '/hello',
to: '/.netlify/functions/hello',
})

await mkdir(generatedFunctionsDir)
await writeFile(
`${generatedFunctionsDir}/hello.js`,
`const { CONTEXT_CHECK, NETLIFY_DEV } = process.env; exports.handler = async () => ({ statusCode: 200, body: JSON.stringify({ CONTEXT_CHECK, NETLIFY_DEV }) })`,
)
},
},
})
.buildAsync()

await withDevServer(
{ cwd: builder.directory, context: null, debug: true, serve: true },
async ({ output, url }) => {
const response = await got(`${url}/hello`).json()
t.deepEqual(response, { CONTEXT_CHECK: 'PRODUCTION' })

t.snapshot(normalize(output, { duration: true, filePath: true }))
},
)
})
})
Loading

1 comment on commit b381412

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📊 Benchmark results

  • Dependency count: 1,313
  • Package size: 271 MB

Please sign in to comment.