@uscreen.de/create-fastify-app 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintcache CHANGED
@@ -1 +1 @@
1
- [{"/Users/marcus/Sites/npm-uscreen/repos/create-fastify-app/bin/cli.js":"1"},{"size":4235,"mtime":1669742140487,"results":"2","hashOfConfig":"3"},{"filePath":"4","messages":"5","suppressedMessages":"6","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"8tgkqw","/Users/marcus/Sites/npm-uscreen/repos/create-fastify-app/bin/cli.js",[],[]]
1
+ [{"/Users/martin/repos/uscreen/npm/create-fastify-app/bin/cli.js":"1","/Users/martin/repos/uscreen/npm/create-fastify-app/test/cli.test.js":"2","/Users/martin/repos/uscreen/npm/create-fastify-app/test/setup.js":"3"},{"size":3522,"mtime":1675168988666,"results":"4","hashOfConfig":"5"},{"size":2397,"mtime":1675169193473,"results":"6","hashOfConfig":"5"},{"size":717,"mtime":1675081403094,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","suppressedMessages":"10","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1ohqtje",{"filePath":"11","messages":"12","suppressedMessages":"13","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14","messages":"15","suppressedMessages":"16","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/martin/repos/uscreen/npm/create-fastify-app/bin/cli.js",[],[],"/Users/martin/repos/uscreen/npm/create-fastify-app/test/cli.test.js",[],[],"/Users/martin/repos/uscreen/npm/create-fastify-app/test/setup.js",[],[]]
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "npm"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
@@ -0,0 +1,51 @@
1
+ # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
3
+
4
+ name: Test CI
5
+
6
+ on:
7
+ push:
8
+ branches: ["master"]
9
+ pull_request:
10
+ branches: ["master"]
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ node-version: [14, 16, 18, 19]
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v3
21
+
22
+ - name: Use Node.js ${{ matrix.node-version }}
23
+ uses: actions/setup-node@v3
24
+ with:
25
+ node-version: ${{ matrix.node-version }}
26
+ cache: "npm"
27
+
28
+ - name: Install packages
29
+ run: npm install
30
+
31
+ - name: Run tests
32
+ run: npm run test:ci
33
+
34
+ - name: Coveralls
35
+ uses: coverallsapp/github-action@master
36
+ with:
37
+ github-token: ${{ secrets.GITHUB_TOKEN }}
38
+
39
+ automerge:
40
+ if: >
41
+ github.event_name == 'pull_request' &&
42
+ github.event.pull_request.user.login == 'dependabot[bot]'
43
+ needs: test
44
+ runs-on: ubuntu-latest
45
+ permissions:
46
+ pull-requests: write
47
+ contents: write
48
+ steps:
49
+ - uses: fastify/github-action-merge-dependabot@v3
50
+ with:
51
+ github-token: ${{ secrets.GITHUB_TOKEN }}
package/.gitignore CHANGED
@@ -2,5 +2,7 @@
2
2
  .DS_Store
3
3
  yarn-error.log
4
4
  /.nyc_output
5
+ /coverage
5
6
  /skeleton/yarn.lock
7
+ /test/_arena
6
8
  /.eslintcache
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # create-fastify-app
2
2
 
3
+ [![Test CI](https://github.com/uscreen/create-fastify-app/actions/workflows/main.yml/badge.svg)](https://github.com/uscreen/create-fastify-app/actions/workflows/main.yml)
4
+ [![Test Coverage](https://coveralls.io/repos/github/uscreen/create-fastify-app/badge.svg?branch=master)](https://coveralls.io/github/uscreen/create-fastify-app?branch=master)
5
+ [![Known Vulnerabilities](https://snyk.io/test/github/uscreen/create-fastify-app/badge.svg?targetFile=package.json)](https://snyk.io/test/github/uscreen/create-fastify-app?targetFile=package.json)
6
+ [![NPM Version](https://badge.fury.io/js/@uscreen.de%2Fcreate-fastify-app.svg)](https://badge.fury.io/js/@uscreen.de%2Fcreate-fastify-app)
7
+
3
8
  > cli to quickly bootstrap a new fastify-app
4
9
 
5
10
  This package provides the cli skript to create a new `@uscreen.de/fastify-app` from scratch. No need to install any other prerequisites than node and yarn. Features include:
package/bin/cli.js CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  import path from 'path'
4
4
  import { fileURLToPath } from 'url'
5
+ import { createRequire } from 'module'
6
+
5
7
  import { program } from 'commander'
6
8
  import { readPackageUpSync } from 'read-pkg-up'
7
9
  import { writePackage } from 'write-pkg'
@@ -11,6 +13,8 @@ import { spawn } from 'child_process'
11
13
 
12
14
  const __filename = fileURLToPath(import.meta.url)
13
15
  const __dirname = path.dirname(__filename)
16
+ const require = createRequire(import.meta.url)
17
+ const { version } = require('../package.json')
14
18
 
15
19
  let root
16
20
  let skeleton
@@ -25,6 +29,7 @@ const initializeGitRepository = (path) =>
25
29
  git.stderr.on('data', (data) => process.stderr.write(data))
26
30
  git.on('close', (code) => {
27
31
  if (code === 0) return resolve(code)
32
+ /* c8 ignore next */
28
33
  reject(code)
29
34
  })
30
35
  })
@@ -32,57 +37,35 @@ const initializeGitRepository = (path) =>
32
37
  /**
33
38
  * init new yarn project
34
39
  */
35
- const initializeYarn = (path) =>
40
+ const initializeYarn = (path, { yes } = {}) =>
36
41
  new Promise((resolve, reject) => {
37
- const yarn = spawn('yarn', ['init'], {
42
+ const params = ['init']
43
+ if (yes) params.push('-y')
44
+
45
+ const yarn = spawn('yarn', params, {
38
46
  cwd: path,
39
47
  stdio: [0, 1, 2]
40
48
  })
41
49
  yarn.on('close', (code) => {
42
50
  if (code === 0) return resolve(code)
51
+ /* c8 ignore next */
43
52
  reject(code)
44
53
  })
45
54
  })
46
55
 
47
56
  /**
48
- * install extra dev packages from skeleleton
49
- */
50
- const installDevPackages = (appPath, skelPath) => {
51
- const skelPack = readPackageUpSync({ cwd: skelPath })
52
- const devDependencies = Object.entries(
53
- skelPack.packageJson.devDependencies
54
- ).map(([key, val]) => `${key}@${val}`)
55
-
56
- return new Promise((resolve, reject) => {
57
- const yarn = spawn('yarn', ['add', ...devDependencies, '-D'], {
58
- cwd: appPath
59
- })
60
- yarn.stdout.on('data', (data) => process.stdout.write(data))
61
- yarn.stderr.on('data', (data) => process.stderr.write(data))
62
- yarn.on('close', (code) => {
63
- if (code === 0) return resolve(code)
64
- reject(code)
65
- })
66
- })
67
- }
68
-
69
- /**
70
- * install extra prod packages from skeleleton
57
+ * install packages
71
58
  */
72
- const installPackages = (appPath, skelPath) => {
73
- const skelPack = readPackageUpSync({ cwd: skelPath })
74
- const dependencies = Object.entries(skelPack.packageJson.dependencies).map(
75
- ([key, val]) => `${key}@${val}`
76
- )
77
-
59
+ const installPackages = (appPath) => {
78
60
  return new Promise((resolve, reject) => {
79
- const yarn = spawn('yarn', ['add', ...dependencies], {
61
+ const yarn = spawn('yarn', ['install'], {
80
62
  cwd: appPath
81
63
  })
82
64
  yarn.stdout.on('data', (data) => process.stdout.write(data))
83
65
  yarn.stderr.on('data', (data) => process.stderr.write(data))
84
66
  yarn.on('close', (code) => {
85
67
  if (code === 0) return resolve(code)
68
+ /* c8 ignore next */
86
69
  reject(code)
87
70
  })
88
71
  })
@@ -102,6 +85,9 @@ const addPackageConfig = (path, skelPath) => {
102
85
  pack.packageJson.scripts = skelPack.packageJson.scripts
103
86
  pack.packageJson['lint-staged'] = skelPack.packageJson['lint-staged']
104
87
 
88
+ pack.packageJson.dependencies = skelPack.packageJson.dependencies
89
+ pack.packageJson.devDependencies = skelPack.packageJson.devDependencies
90
+
105
91
  return writePackage(pack.path, pack.packageJson)
106
92
  }
107
93
 
@@ -129,14 +115,10 @@ const copyEnv = (appPath, skelPath) => {
129
115
  * define the command
130
116
  */
131
117
  program
132
- .version('0.1.0')
133
- .arguments('<name> [opt]')
118
+ .version(version)
119
+ .arguments('<name>')
120
+ .option('-y --yes')
134
121
  .action(async (name, opt) => {
135
- if (typeof name === 'undefined') {
136
- console.error('please specify your new apps name...')
137
- process.exit(1)
138
- }
139
-
140
122
  /**
141
123
  * the root directory of new project
142
124
  */
@@ -151,10 +133,9 @@ program
151
133
  * setup new app
152
134
  */
153
135
  await initializeGitRepository(root)
154
- await initializeYarn(root)
155
- await installDevPackages(root, skeleton)
156
- await installPackages(root, skeleton)
136
+ await initializeYarn(root, opt)
157
137
  await addPackageConfig(root, skeleton)
138
+ await installPackages(root)
158
139
  await copySkeleton(root, skeleton)
159
140
  await copyEnv(root, skeleton)
160
141
  })
@@ -163,10 +144,3 @@ program
163
144
  * read args
164
145
  */
165
146
  program.parse(process.argv)
166
-
167
- /**
168
- * output help as default
169
- */
170
- if (!process.argv.slice(2).length) {
171
- program.help()
172
- }
package/package.json CHANGED
@@ -1,29 +1,39 @@
1
1
  {
2
2
  "name": "@uscreen.de/create-fastify-app",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "cli to create a new @uscreen.de/fastify-app",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
- "repository": "git@gitlab.uscreen.net:uscreen/npm/create-fastify-app.git",
7
+ "homepage": "https://github.com/uscreen/create-fastify-app",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/uscreen/create-fastify-app.git"
11
+ },
8
12
  "author": "Marcus Spiegel <spiegel@uscreen.de>",
9
13
  "license": "MIT",
10
14
  "bin": {
11
15
  "create-fastify-app": "./bin/cli.js"
12
16
  },
13
17
  "scripts": {
18
+ "test": "c8 tap",
19
+ "test:cov": "c8 --reporter=html --reporter=text tap",
20
+ "test:ci": "c8 --reporter=lcovonly tap",
14
21
  "lint": "eslint --fix",
15
22
  "prepare": "husky install"
16
23
  },
17
24
  "dependencies": {
18
- "commander": "^9.4.1",
19
- "fs-extra": "^10.0.1",
25
+ "commander": "^10.0.0",
26
+ "fs-extra": "^11.1.0",
20
27
  "read-pkg-up": "^9.1.0",
21
28
  "write-pkg": "^5.0.0"
22
29
  },
23
30
  "devDependencies": {
24
31
  "@uscreen.de/eslint-config-prettystandard-node": "^0.2.10",
32
+ "c8": "^7.12.0",
25
33
  "husky": ">=8.0.2",
26
- "lint-staged": ">=13.0.3"
34
+ "lint-staged": ">=13.0.3",
35
+ "strip-ansi": "^7.0.1",
36
+ "tap": "^16.3.4"
27
37
  },
28
38
  "lint-staged": {
29
39
  "*.js": "eslint --cache --fix"
package/skeleton/.nvmrc CHANGED
@@ -1 +1 @@
1
- 16
1
+ 18
@@ -0,0 +1,13 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ indent_style = space
6
+ indent_size = 2
7
+ end_of_line = lf
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
10
+
11
+ [{Makefile,**.mk}]
12
+ # Use tabs for indentation (Makefiles require tabs)
13
+ indent_style = tab
@@ -0,0 +1,4 @@
1
+ # @see ./app/config.js for defaults and options
2
+
3
+ logLevel = debug
4
+
@@ -0,0 +1,4 @@
1
+ # @see https://direnv.net/ and https://github.com/direnv/direnv/wiki/Node for docs
2
+ set -e
3
+ use node
4
+ layout node
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "@uscreen.de/eslint-config-prettystandard-node"
3
+ }
@@ -0,0 +1,7 @@
1
+ node_modules
2
+ /.env
3
+ /.nyc_output
4
+ /coverage
5
+ .DS_Store
6
+ yarn-error.log
7
+ /.eslintcache
@@ -0,0 +1,25 @@
1
+ # image: node:lts-alpine
2
+
3
+ # cache:
4
+ # paths:
5
+ # - node_modules/
6
+ # - .yarn
7
+
8
+ # stages:
9
+ # - test
10
+ # - audit
11
+
12
+ # test:
13
+ # stage: test
14
+ # script:
15
+ # - npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
16
+ # - yarn install --pure-lockfile --cache-folder .yarn
17
+ # - yarn test:ci
18
+ # coverage: '/^Statements\s*:\s*([^%]+)/'
19
+
20
+ # audit:
21
+ # stage: audit
22
+ # only:
23
+ # - schedules
24
+ # script:
25
+ # - yarn audit
@@ -0,0 +1 @@
1
+ 18
@@ -0,0 +1,7 @@
1
+ {
2
+ "timeout": 10,
3
+ "reporter": "spec",
4
+ "check-coverage": false,
5
+ "no-coverage": true,
6
+ "test-regex": "\\w+\\.test\\.js$"
7
+ }
@@ -0,0 +1,11 @@
1
+ start:
2
+ yarn
3
+ yarn dev
4
+
5
+ test:
6
+ yarn test
7
+
8
+ test.coverage:
9
+ yarn test:cov
10
+
11
+ .PHONY: test
@@ -0,0 +1,38 @@
1
+ # ${app-name}
2
+
3
+ > __TODO:__
4
+ > add a name & short description of this apps purpose
5
+
6
+ ## Usage
7
+
8
+ * `make start`: start app on local dev
9
+ * `make test`: test app
10
+
11
+ ## Configure
12
+
13
+ Configuration is read by dotenv from `app/.env` file and validated _[optional modified]_ by `app/config.js`. Please add extra defaults if needed to `config.js`. Default values should __always__ refer to local dev setups.
14
+
15
+ > __Note:__
16
+ > the `.env` file should __never__ get pushed to repository. So adding secrets and credentials to `.env` can be considered a secure option bound to specific environments.
17
+
18
+ ## Api
19
+
20
+ After starting your server you will find swagger documenation at [http://127.0.0.1:3000/api/docs/](http://127.0.0.1:3000/api/docs/) to explore web api requests interactively.
21
+
22
+ ---
23
+
24
+ ## Roadmap
25
+
26
+ > TBD
27
+
28
+ ## Changelog
29
+
30
+ ### v0.0.0
31
+
32
+ - initially bootstrapped by `yarn create @uscreen.de/fastify-app`
33
+
34
+ ---
35
+
36
+ ## Credits
37
+
38
+ application [boilerplate](https://www.npmjs.com/package/@uscreen.de/fastify-app) provided by [u|screen](https://uscreen.de)
@@ -0,0 +1,17 @@
1
+ import fastifyApp from '@uscreen.de/fastify-app'
2
+ import fp from 'fastify-plugin'
3
+ import schemas from './schemas.js'
4
+
5
+ export default fp((fastify, opts, next) => {
6
+ /**
7
+ * add schemas
8
+ */
9
+ fastify.register(schemas)
10
+
11
+ /**
12
+ * register app
13
+ */
14
+ fastify.register(fastifyApp, opts)
15
+
16
+ next()
17
+ })
@@ -0,0 +1,34 @@
1
+ import envSchema from 'env-schema'
2
+ import CommonESM from '@uscreen.de/common-esm'
3
+
4
+ const { join } = new CommonESM(import.meta.url)
5
+
6
+ const schema = {
7
+ type: 'object',
8
+ properties: {
9
+ httpPort: { default: 3000 },
10
+ httpBind: { default: '127.0.0.1' },
11
+ prefix: { default: '/api' },
12
+ logEnabled: { default: true },
13
+ logLevel: { default: 'info' }
14
+ }
15
+ }
16
+
17
+ const config = envSchema({
18
+ schema: schema,
19
+ dotenv: true
20
+ })
21
+
22
+ config.autoloads = [join('plugins'), join('services')]
23
+
24
+ config.swagger = {
25
+ routePrefix: `${config.prefix}/docs`,
26
+ exposeRoute: true,
27
+ addModels: true
28
+ }
29
+
30
+ config.health = {
31
+ exposeStatusRoute: `${config.prefix}/health`
32
+ }
33
+
34
+ export default config
@@ -0,0 +1,14 @@
1
+ import fp from 'fastify-plugin'
2
+
3
+ export default fp(
4
+ (fastify, opts, next) => {
5
+ fastify.decorate('noop', () => {
6
+ return 'Hello Universe'
7
+ })
8
+
9
+ next()
10
+ },
11
+ {
12
+ name: 'noop'
13
+ }
14
+ )
@@ -0,0 +1,34 @@
1
+ import fp from 'fastify-plugin'
2
+ import S from 'fluent-json-schema'
3
+
4
+ /**
5
+ * Usage of the Globaly Shared Schema feature
6
+ */
7
+
8
+ export default fp((fastify, opts, next) => {
9
+ const addSchema = (schema) => {
10
+ fastify.addSchema(schema)
11
+ return schema
12
+ }
13
+
14
+ /**
15
+ * add generic schemas
16
+ */
17
+ const noop = addSchema(S.object().id('noop').prop('noop'))
18
+
19
+ const plugin = addSchema(S.object().id('plugin').prop('plugin'))
20
+
21
+ /**
22
+ * combine and extend schemas
23
+ */
24
+ addSchema(
25
+ S.object()
26
+ .id('noopNplugin')
27
+ .required(['noop'])
28
+ // .prop('property') // --> strip it
29
+ .extend(noop)
30
+ .extend(plugin)
31
+ )
32
+
33
+ next()
34
+ })
@@ -0,0 +1,37 @@
1
+ import fastify from 'fastify'
2
+ import { options } from '@uscreen.de/fastify-app'
3
+ import config from './config.js'
4
+ import app from './app.js'
5
+
6
+ const server = fastify(options(config))
7
+
8
+ server.register(app, config)
9
+
10
+ /**
11
+ * post-treatment
12
+ */
13
+ server.ready((err) => {
14
+ if (err) throw err
15
+ server.log.debug(
16
+ 'server ready, routes are set:\n' +
17
+ server.printRoutes({ commonPrefix: false })
18
+ )
19
+ })
20
+
21
+ /**
22
+ * graceful shutdown (closing handles, etc.)
23
+ */
24
+ const shutdown = async () => {
25
+ server.log.info(
26
+ `application shutting down. (${server.app.name} ${server.app.version})`
27
+ )
28
+ await server.close()
29
+ process.exit()
30
+ }
31
+ process.on('SIGINT', shutdown)
32
+ process.on('SIGTERM', shutdown)
33
+
34
+ /**
35
+ * start http server
36
+ */
37
+ server.listen({ port: config.httpPort, host: config.httpBind })
@@ -0,0 +1,22 @@
1
+ export default (fastify, opts, next) => {
2
+ fastify.get(
3
+ '/noop',
4
+ {
5
+ schema: {
6
+ response: {
7
+ 200: { $ref: 'noopNplugin#' } // fastest and json-schema spec compatiple way, or use 'fastify.getSchema()'
8
+ // 200: fastify.getSchema('noopNplugin')
9
+ }
10
+ }
11
+ },
12
+ async (req, res) => {
13
+ return {
14
+ noop: 'Hello world',
15
+ plugin: fastify.noop(),
16
+ property: 'should be stripped from response'
17
+ }
18
+ }
19
+ )
20
+
21
+ next()
22
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "new-app",
3
+ "version": "1.0.0",
4
+ "main": "app/server.js",
5
+ "author": {
6
+ "name": "Martin Herting",
7
+ "email": "herting@uscreen.de"
8
+ },
9
+ "license": "MIT",
10
+ "type": "module",
11
+ "scripts": {
12
+ "dev": "nodemon",
13
+ "lint": "eslint --fix",
14
+ "test": "c8 tap",
15
+ "test:cov": "c8 --reporter=html --reporter=text tap",
16
+ "test:ci": "tap",
17
+ "prepare": "husky install"
18
+ },
19
+ "lint-staged": {
20
+ "*.js": "eslint --cache --fix"
21
+ },
22
+ "dependencies": {
23
+ "@uscreen.de/common-esm": "^1.0.0",
24
+ "@uscreen.de/fastify-app": "^1.0.0-0",
25
+ "env-schema": "^5.1.1",
26
+ "fastify": "^4.10.2",
27
+ "fastify-plugin": "^4.3.0",
28
+ "fluent-json-schema": "^4.0.0",
29
+ "pino-pretty": "^9.1.1"
30
+ },
31
+ "devDependencies": {
32
+ "@uscreen.de/eslint-config-prettystandard-node": "^0.2.8",
33
+ "c8": "^7.12.0",
34
+ "husky": ">=6",
35
+ "lint-staged": ">=10",
36
+ "nodemon": "^2.0.20",
37
+ "prettier": "^2.8.0",
38
+ "tap": "^16.3.2"
39
+ }
40
+ }
@@ -0,0 +1,54 @@
1
+ import tap from 'tap'
2
+ import { build } from '../helper.js'
3
+
4
+ tap.test('Test Setup', (t) => {
5
+ t.equal(true, true, 'Tests and assertions should work')
6
+ t.end()
7
+ })
8
+
9
+ tap.test('Healthcheck', async (t) => {
10
+ const fastify = await build(t)
11
+ const { prefix } = fastify.config
12
+
13
+ t.test('a valid GET Request', (t) => {
14
+ fastify.inject(
15
+ {
16
+ method: 'GET',
17
+ url: `${prefix}/health`
18
+ },
19
+ (e, response) => {
20
+ t.error(e)
21
+ t.same(response.statusCode, 200, 'response ok')
22
+ t.same(JSON.parse(response.body), { status: 'ok' }, 'payload ok')
23
+ t.end()
24
+ }
25
+ )
26
+ })
27
+ })
28
+
29
+ tap.test('Noop Service', async (t) => {
30
+ const fastify = await build(t)
31
+ const { prefix } = fastify.config
32
+
33
+ t.test('a valid GET Request', (t) => {
34
+ fastify.inject(
35
+ {
36
+ method: 'GET',
37
+ url: `${prefix}/noop`
38
+ },
39
+ (e, response) => {
40
+ t.error(e)
41
+ t.same(response.statusCode, 200, 'response ok')
42
+ t.same(
43
+ JSON.parse(response.body),
44
+ {
45
+ noop: 'Hello world',
46
+ plugin: 'Hello Universe'
47
+ },
48
+ 'payload ok'
49
+ )
50
+ t.end()
51
+ }
52
+ )
53
+ })
54
+ })
@@ -0,0 +1,29 @@
1
+ // This file contains code that we reuse
2
+ // between our tests.
3
+
4
+ import Fastify from 'fastify'
5
+ import fp from 'fastify-plugin'
6
+
7
+ // setup to import YOUR app
8
+ import App from '../app/app.js'
9
+ import Config from '../app/config.js'
10
+
11
+ // automatically build and tear down our instance
12
+ export const build = async (t, ConfigOverwrite = {}) => {
13
+ return new Promise((resolve) => {
14
+ const app = Fastify()
15
+
16
+ // setup to register YOUR app
17
+ app.register(fp(App), { ...Config, ...ConfigOverwrite })
18
+
19
+ // tear down our app after we are done
20
+ t.teardown(app.close.bind(app))
21
+
22
+ app.ready((err) => {
23
+ if (err) throw err
24
+ resolve(app)
25
+ })
26
+ })
27
+ }
28
+
29
+ export const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
@@ -0,0 +1,109 @@
1
+ import tap from 'tap'
2
+ import fs from 'fs-extra'
3
+ import path from 'path'
4
+ import { createRequire } from 'module'
5
+ import stripAnsi from 'strip-ansi'
6
+ import { before, teardown, cli, cwd } from './setup.js'
7
+
8
+ const require = createRequire(import.meta.url)
9
+ const { version } = require('../package.json')
10
+
11
+ tap.before(before)
12
+ tap.teardown(teardown)
13
+
14
+ tap.test('$ cli', async (t) => {
15
+ const result = await cli([])
16
+ t.equal(
17
+ true,
18
+ result.stderr.startsWith("error: missing required argument 'name'"),
19
+ 'Should print error message'
20
+ )
21
+
22
+ t.end()
23
+ })
24
+
25
+ tap.test('$ cli -V', async (t) => {
26
+ const result = await cli(['--version'])
27
+ t.equal(
28
+ true,
29
+ result.stdout.startsWith(version),
30
+ 'Should show correct version'
31
+ )
32
+
33
+ t.end()
34
+ })
35
+
36
+ tap.test('$ cli new-app -y', async (t) => {
37
+ const result = await cli(['new-app', '-y'])
38
+
39
+ /**
40
+ * check output
41
+ */
42
+ t.equal(0, result.code, 'Should succeed')
43
+
44
+ t.test('Check output', (t) => {
45
+ const expectedOut = [
46
+ `Initialized empty Git repository in ${path.resolve(
47
+ cwd,
48
+ 'new-app',
49
+ '.git'
50
+ )}`,
51
+ 'success Saved package.json',
52
+ '[1/4] Resolving packages...',
53
+ '[2/4] Fetching packages...',
54
+ '[3/4] Linking dependencies...',
55
+ '[4/4] Building fresh packages...',
56
+ 'success Saved lockfile.',
57
+ 'husky - Git hooks installed'
58
+ ]
59
+
60
+ const stdout = stripAnsi(result.stdout)
61
+
62
+ for (const e of expectedOut) {
63
+ t.equal(true, stdout.includes(e), `"${e.substring(0, 36)}"`)
64
+ }
65
+
66
+ t.end()
67
+ })
68
+
69
+ /**
70
+ * check files
71
+ */
72
+ t.test('Check files', (t) => {
73
+ const appPath = path.resolve(cwd, 'new-app')
74
+
75
+ t.equal(
76
+ true,
77
+ fs.existsSync(path.resolve(appPath, 'package.json')),
78
+ 'package.json was created'
79
+ )
80
+ t.equal(
81
+ true,
82
+ fs.existsSync(path.resolve(appPath, 'README.md')),
83
+ 'skeleton was copied'
84
+ )
85
+ t.equal(
86
+ true,
87
+ fs.existsSync(path.resolve(appPath, 'yarn.lock')),
88
+ 'Packages were installed'
89
+ )
90
+
91
+ const pack = JSON.parse(
92
+ fs.readFileSync(path.resolve(appPath, 'package.json'), {
93
+ encoding: 'utf-8'
94
+ })
95
+ )
96
+ t.equal(
97
+ true,
98
+ pack.name !== 'new-fastify-app',
99
+ 'package.json was not just copied from skeleton'
100
+ )
101
+ t.equal(
102
+ true,
103
+ pack.main === 'app/server.js',
104
+ 'package.json was correctly enriched with data'
105
+ )
106
+
107
+ t.end()
108
+ })
109
+ })
package/test/setup.js ADDED
@@ -0,0 +1,33 @@
1
+ import fs from 'fs-extra'
2
+ import path from 'path'
3
+ import { exec } from 'child_process'
4
+ import { fileURLToPath } from 'url'
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
7
+
8
+ export const cwd = path.resolve(__dirname, './_arena/')
9
+
10
+ export const cli = (args) => {
11
+ return new Promise((resolve) => {
12
+ exec(
13
+ `node ${path.resolve(__dirname, '../bin/cli.js')} ${args.join(' ')}`,
14
+ { cwd },
15
+ (error, stdout, stderr) => {
16
+ resolve({
17
+ code: error && error.code ? error.code : 0,
18
+ error,
19
+ stdout,
20
+ stderr
21
+ })
22
+ }
23
+ )
24
+ })
25
+ }
26
+
27
+ export const before = () => {
28
+ fs.ensureDirSync(cwd)
29
+ }
30
+
31
+ export const teardown = () => {
32
+ fs.removeSync(cwd)
33
+ }