create-platformatic 1.49.1 → 1.51.8

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.
@@ -0,0 +1,80 @@
1
+ import { test } from 'node:test'
2
+ import { equal } from 'node:assert'
3
+ import { timeout } from './timeout.mjs'
4
+ import { isFileAccessible } from '../../src/utils.mjs'
5
+ import { join } from 'node:path'
6
+ import { tmpdir } from 'os'
7
+ import { mkdtemp, rm } from 'fs/promises'
8
+ import {
9
+ executeCreatePlatformatic,
10
+ startMarketplace,
11
+ keys,
12
+ walk,
13
+ getServices
14
+ } from './helper.mjs'
15
+
16
+ let tmpDir
17
+ test.beforeEach(async () => {
18
+ tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
19
+ })
20
+
21
+ test.afterEach(async () => {
22
+ try {
23
+ await rm(tmpDir, { recursive: true, force: true })
24
+ } catch (e) {
25
+ // on purpose, in win the resource might be still "busy"
26
+ }
27
+ })
28
+
29
+ test('Creates a Platformatic Composer', { timeout }, async (t) => {
30
+ const marketplaceHost = await startMarketplace(t)
31
+ // The actions must match IN ORDER
32
+ const actions = [{
33
+ match: 'What kind of project do you want to create?',
34
+ do: [keys.ENTER] // Application
35
+ }, {
36
+ match: 'Where would you like to create your project?',
37
+ do: [keys.ENTER],
38
+ waitAfter: 8000
39
+ }, {
40
+ match: 'Which kind of project do you want to create?',
41
+ do: [keys.UP, keys.UP, keys.ENTER] // Composer
42
+ }, {
43
+ match: 'What is the name of the service?',
44
+ do: [keys.ENTER]
45
+ }, {
46
+ match: 'Do you want to create another service?',
47
+ do: [keys.DOWN, keys.ENTER] // no
48
+ }, {
49
+ // NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
50
+ match: 'Do you want to use TypeScript',
51
+ do: [keys.ENTER], // no
52
+ waitAfter: 8000
53
+ }, {
54
+ match: 'What port do you want to use?',
55
+ do: [keys.ENTER]
56
+ }, {
57
+ match: 'Do you want to init the git repository',
58
+ do: [keys.DOWN, keys.ENTER] // yes
59
+ }]
60
+ await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
61
+
62
+ const baseProjectDir = join(tmpDir, 'platformatic')
63
+ const files = await walk(baseProjectDir)
64
+ console.log('==> created files', files)
65
+ equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
66
+ equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
67
+ equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
68
+ equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
69
+ equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
70
+
71
+ // Here check the generated service
72
+ const services = await getServices(join(baseProjectDir, 'services'))
73
+ equal(services.length, 1)
74
+ const baseServiceDir = join(baseProjectDir, 'services', services[0])
75
+ console.log(baseServiceDir)
76
+ equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
77
+ equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
78
+ equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
79
+ equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
80
+ })
@@ -0,0 +1,86 @@
1
+ import { test } from 'node:test'
2
+ import { equal } from 'node:assert'
3
+ import { timeout } from './timeout.mjs'
4
+ import { isFileAccessible } from '../../src/utils.mjs'
5
+ import { join } from 'node:path'
6
+ import { tmpdir } from 'os'
7
+ import { mkdtemp, rm } from 'fs/promises'
8
+ import {
9
+ executeCreatePlatformatic,
10
+ startMarketplace,
11
+ keys,
12
+ walk,
13
+ getServices
14
+ } from './helper.mjs'
15
+
16
+ let tmpDir
17
+ test.beforeEach(async () => {
18
+ tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
19
+ })
20
+
21
+ test.afterEach(async () => {
22
+ try {
23
+ await rm(tmpDir, { recursive: true, force: true })
24
+ } catch (e) {
25
+ // on purpose, in win the resource might be still "busy"
26
+ }
27
+ })
28
+
29
+ test('Creates a Platformatic DB service with no migrations', { timeout }, async (t) => {
30
+ const marketplaceHost = await startMarketplace(t)
31
+ // The actions must match IN ORDER
32
+ const actions = [{
33
+ match: 'What kind of project do you want to create?',
34
+ do: [keys.ENTER] // Application
35
+ }, {
36
+ match: 'Where would you like to create your project?',
37
+ do: [keys.ENTER],
38
+ waitAfter: 8000
39
+ }, {
40
+ match: 'Which kind of project do you want to create?',
41
+ do: [keys.UP, keys.ENTER] // DB
42
+ }, {
43
+ match: 'What is the name of the service?',
44
+ do: [keys.ENTER]
45
+ }, {
46
+ match: 'What is the connection string?',
47
+ do: [keys.ENTER]
48
+ }, {
49
+ match: 'Do you want to create default migrations',
50
+ do: [keys.DOWN, keys.ENTER] // no
51
+ }, {
52
+ match: 'Do you want to create another service?',
53
+ do: [keys.DOWN, keys.ENTER] // no
54
+ }, {
55
+ // NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
56
+ match: 'Do you want to use TypeScript',
57
+ do: [keys.ENTER] // no
58
+ }, {
59
+ match: 'What port do you want to use?',
60
+ do: [keys.ENTER]
61
+ }, {
62
+ match: 'Do you want to init the git repository',
63
+ do: [keys.DOWN, keys.ENTER] // yes
64
+ }]
65
+ await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
66
+
67
+ const baseProjectDir = join(tmpDir, 'platformatic')
68
+ const files = await walk(baseProjectDir)
69
+ console.log('==> created files', files)
70
+ equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
71
+ equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
72
+ equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
73
+ equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
74
+ equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
75
+
76
+ // Here check the generated service
77
+ const services = await getServices(join(baseProjectDir, 'services'))
78
+ equal(services.length, 1)
79
+ const baseServiceDir = join(baseProjectDir, 'services', services[0])
80
+ console.log(baseServiceDir)
81
+ equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
82
+ equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
83
+ equal(await isFileAccessible(join(baseServiceDir, 'migrations')), false)
84
+ equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
85
+ equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
86
+ })
@@ -0,0 +1,159 @@
1
+ import os from 'node:os'
2
+ import { execa } from 'execa'
3
+ import { join } from 'desm'
4
+ import stripAnsi from 'strip-ansi'
5
+ import { promisify } from 'node:util'
6
+ import { promises as fs } from 'node:fs'
7
+ import path from 'node:path'
8
+ import fastify from 'fastify'
9
+
10
+ const sleep = promisify(setTimeout)
11
+
12
+ export const keys = {
13
+ DOWN: '\x1B\x5B\x42',
14
+ UP: '\x1B\x5B\x41',
15
+ ENTER: '\x0D',
16
+ SPACE: '\x20'
17
+ }
18
+
19
+ export const createPath = join(import.meta.url, '..', '..', 'create-platformatic.mjs')
20
+
21
+ const match = (str, match) => {
22
+ if (Array.isArray(match)) {
23
+ return match.some((m) => str.includes(m))
24
+ }
25
+ return str.includes(match)
26
+ }
27
+
28
+ export const walk = async (dir) => {
29
+ let files = await fs.readdir(dir)
30
+ files = await Promise.all(files.map(async file => {
31
+ const filePath = path.join(dir, file)
32
+ const stats = await fs.stat(filePath)
33
+ if (stats.isDirectory()) return walk(filePath)
34
+ else if (stats.isFile()) return filePath
35
+ }))
36
+ return files.reduce((all, folderContents) => all.concat(folderContents), [])
37
+ }
38
+
39
+ export const getServices = async (dir) => {
40
+ const files = await fs.readdir(dir)
41
+ const services = []
42
+ for (const file of files) {
43
+ services.push(file)
44
+ }
45
+ return services
46
+ }
47
+
48
+ // Actions are in the form:
49
+ // {
50
+ // match: 'Server listening at',
51
+ // do: [keys.DOWN, keys.ENTER]
52
+ // }
53
+ export async function executeCreatePlatformatic (dir, actions = [], options = {}) {
54
+ const done = options.done || 'You are all set!'
55
+ const pkgMgrInstall = options.pkgMgrInstall || false
56
+ const pkgManager = options.pkgManager || 'npm'
57
+ const marketplaceHost = options.marketplaceHost
58
+
59
+ const runCreatePlatformatic = async () => {
60
+ const questions = [...actions]
61
+ try {
62
+ const execaOptions = {
63
+ cwd: dir
64
+ }
65
+
66
+ if (pkgManager === 'pnpm') {
67
+ execaOptions.env = {
68
+ npm_config_user_agent: 'pnpm/6.14.1 npm/? node/v16.4.2 darwin x64'
69
+ }
70
+ }
71
+
72
+ const child = execa('node', [
73
+ createPath,
74
+ `--install=${pkgMgrInstall.toString()}`,
75
+ `--marketplace-host=${marketplaceHost}`
76
+ ], execaOptions)
77
+
78
+ // We just need the "lastPrompt" printed before the process stopped to wait for an answer
79
+ // If we don't have any outptu from process for more than 500ms, we assume it's waiting for an answer
80
+ let lastPrompt = ''
81
+
82
+ child.stdout.on('data', (chunk) => {
83
+ const str = stripAnsi(chunk.toString()).trim()
84
+ if (str) {
85
+ lastPrompt = str
86
+ }
87
+ })
88
+
89
+ let expectedQuestion = questions.shift()
90
+
91
+ // We need this because the prompt prints an introduction before asking anything.
92
+ // If we don't like this, we could use a flag to recognize when the introduction is done
93
+ await sleep(5000)
94
+
95
+ while (true) {
96
+ if (!expectedQuestion) {
97
+ await sleep(500)
98
+ // We processed all expected questions, so now we wait for the process to be done.
99
+ // If the "done" string is not printed, the test will timeout
100
+ if (lastPrompt && lastPrompt.includes(done)) {
101
+ safeKill(child)
102
+ return
103
+ }
104
+ } else if (match(lastPrompt, expectedQuestion.match)) {
105
+ console.log('==> MATCH', expectedQuestion.match)
106
+ lastPrompt = ''
107
+
108
+ for (const key of expectedQuestion.do) {
109
+ child.stdin?.write(key)
110
+ const waitAfter = expectedQuestion.waitAfter || 500
111
+ await sleep(waitAfter)
112
+ }
113
+ expectedQuestion = questions.shift()
114
+ } else {
115
+ throw new Error(`Expected ${expectedQuestion.match}, got ${lastPrompt}`)
116
+ }
117
+ }
118
+ } catch (err) {
119
+ console.error(err)
120
+ throw err
121
+ }
122
+ }
123
+ await runCreatePlatformatic()
124
+ }
125
+
126
+ export async function safeKill (child) {
127
+ child.kill('SIGINT')
128
+ if (os.platform() === 'win32') {
129
+ try {
130
+ await execa('taskkill', ['/pid', child.pid, '/f', '/t'])
131
+ } catch (err) {
132
+ if (err.stderr.indexOf('not found') === 0) {
133
+ console.error(`Failed to kill process ${child.pid}`)
134
+ console.error(err)
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ export async function startMarketplace (t, opts = {}) {
141
+ const marketplace = fastify()
142
+
143
+ marketplace.get('/templates', async (request, reply) => {
144
+ if (opts.templatesCallback) {
145
+ return opts.templatesCallback(request, reply)
146
+ }
147
+ return [
148
+ { name: '@platformatic/composer' },
149
+ { name: '@platformatic/db' },
150
+ { name: '@platformatic/service' }
151
+ ]
152
+ })
153
+
154
+ await marketplace.listen({ port: 0 })
155
+ t.after(() => marketplace.close())
156
+
157
+ const address = marketplace.server.address()
158
+ return `http://127.0.0.1:${address.port}`
159
+ }
@@ -0,0 +1,104 @@
1
+ import { test } from 'node:test'
2
+ import { equal } from 'node:assert'
3
+ import { join } from 'node:path'
4
+ import { tmpdir } from 'node:os'
5
+ import { mkdtemp, rm } from 'node:fs/promises'
6
+ import { timeout } from './timeout.mjs'
7
+ import { isFileAccessible } from '../../src/utils.mjs'
8
+ import {
9
+ executeCreatePlatformatic,
10
+ startMarketplace,
11
+ keys,
12
+ walk,
13
+ getServices
14
+ } from './helper.mjs'
15
+
16
+ let tmpDir
17
+ test.beforeEach(async () => {
18
+ tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
19
+ })
20
+
21
+ test.afterEach(async () => {
22
+ try {
23
+ await rm(tmpDir, { recursive: true, force: true })
24
+ } catch (e) {
25
+ // on purpose, in win the resource might be still "busy"
26
+ }
27
+ })
28
+
29
+ test('Creates a Platformatic Runtime with two Services', { timeout }, async (t) => {
30
+ const marketplaceHost = await startMarketplace(t)
31
+ // The actions must match IN ORDER
32
+ const actions = [{
33
+ match: 'What kind of project do you want to create?',
34
+ do: [keys.ENTER] // Application
35
+ }, {
36
+ match: 'Where would you like to create your project?',
37
+ do: [keys.ENTER],
38
+ waitAfter: 8000
39
+ }, {
40
+ match: 'Which kind of project do you want to create?',
41
+ do: [keys.ENTER] // Service
42
+ }, {
43
+ match: 'What is the name of the service?',
44
+ do: [keys.ENTER]
45
+ }, {
46
+ match: 'Do you want to create another service?',
47
+ do: [keys.ENTER] // yes
48
+ }, {
49
+ match: 'Which kind of project do you want to create?',
50
+ do: [keys.ENTER] // Service
51
+ }, {
52
+ match: 'What is the name of the service?',
53
+ do: [keys.ENTER]
54
+ }, {
55
+ match: 'Do you want to create another service?',
56
+ do: [keys.DOWN, keys.ENTER] // no
57
+ }, {
58
+ match: 'Which service should be exposed?',
59
+ do: [keys.ENTER]
60
+ }, {
61
+ match: 'Do you want to use TypeScript',
62
+ do: [keys.DOWN, keys.ENTER] // yes
63
+ }, {
64
+ match: 'What port do you want to use?',
65
+ do: [keys.ENTER]
66
+ }, {
67
+ match: 'Do you want to init the git repository',
68
+ do: [keys.DOWN, keys.ENTER] // yes
69
+ }]
70
+ await executeCreatePlatformatic(tmpDir, actions, {
71
+ marketplaceHost,
72
+ pkgManager: 'pnpm'
73
+ })
74
+
75
+ const baseProjectDir = join(tmpDir, 'platformatic')
76
+ const files = await walk(baseProjectDir)
77
+ console.log('==> created files', files)
78
+ equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
79
+ equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
80
+ equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
81
+ equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
82
+ equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
83
+ equal(await isFileAccessible(join(baseProjectDir, '.git', 'config')), true)
84
+
85
+ // using pnpm will create workspace file
86
+ equal(await isFileAccessible(join(baseProjectDir, 'pnpm-workspace.yaml')), true)
87
+
88
+ // Here check the generated services
89
+ const services = await getServices(join(baseProjectDir, 'services'))
90
+ equal(services.length, 2)
91
+ const baseService0Dir = join(baseProjectDir, 'services', services[0])
92
+ equal(await isFileAccessible(join(baseService0Dir, 'platformatic.json')), true)
93
+ equal(await isFileAccessible(join(baseService0Dir, 'README.md')), true)
94
+ equal(await isFileAccessible(join(baseService0Dir, 'routes', 'root.ts')), true)
95
+ equal(await isFileAccessible(join(baseService0Dir, 'plugins', 'example.ts')), true)
96
+ equal(await isFileAccessible(join(baseService0Dir, 'global.d.ts')), true)
97
+
98
+ const baseService1Dir = join(baseProjectDir, 'services', services[1])
99
+ equal(await isFileAccessible(join(baseService1Dir, 'platformatic.json')), true)
100
+ equal(await isFileAccessible(join(baseService1Dir, 'README.md')), true)
101
+ equal(await isFileAccessible(join(baseService1Dir, 'routes', 'root.ts')), true)
102
+ equal(await isFileAccessible(join(baseService1Dir, 'plugins', 'example.ts')), true)
103
+ equal(await isFileAccessible(join(baseService1Dir, 'global.d.ts')), true)
104
+ })
@@ -0,0 +1,200 @@
1
+ import { test } from 'node:test'
2
+ import { equal, notEqual } from 'node:assert'
3
+ import { timeout } from './timeout.mjs'
4
+ import { isFileAccessible, safeMkdir } from '../../src/utils.mjs'
5
+ import { join } from 'node:path'
6
+ import { tmpdir } from 'os'
7
+ import { readFile, mkdtemp, rm, writeFile } from 'node:fs/promises'
8
+ import {
9
+ executeCreatePlatformatic,
10
+ startMarketplace,
11
+ keys,
12
+ walk,
13
+ getServices
14
+ } from './helper.mjs'
15
+
16
+ let tmpDir
17
+ test.beforeEach(async () => {
18
+ tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
19
+ })
20
+
21
+ test.afterEach(async () => {
22
+ try {
23
+ await rm(tmpDir, { recursive: true, force: true })
24
+ } catch (e) {
25
+ // on purpose, in win the resource might be still "busy"
26
+ }
27
+ })
28
+
29
+ test('Creates a Platformatic Service with no typescript', { timeout }, async (t) => {
30
+ const marketplaceHost = await startMarketplace(t)
31
+ // The actions must match IN ORDER
32
+ const actions = [{
33
+ match: 'What kind of project do you want to create?',
34
+ do: [keys.ENTER] // Application
35
+ }, {
36
+ match: 'Where would you like to create your project?',
37
+ do: [keys.ENTER],
38
+ waitAfter: 8000
39
+ }, {
40
+ match: 'Which kind of project do you want to create?',
41
+ do: [keys.ENTER] // Service
42
+ }, {
43
+ match: 'What is the name of the service?',
44
+ do: [keys.ENTER]
45
+ }, {
46
+ match: 'Do you want to create another service?',
47
+ do: [keys.DOWN, keys.ENTER] // no
48
+ }, {
49
+ // NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
50
+ match: 'Do you want to use TypeScript',
51
+ do: [keys.ENTER] // no
52
+ }, {
53
+ match: 'What port do you want to use?',
54
+ do: [keys.ENTER]
55
+ }, {
56
+ match: 'Do you want to init the git repository',
57
+ do: [keys.DOWN, keys.ENTER] // yes
58
+ }]
59
+ await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
60
+
61
+ const baseProjectDir = join(tmpDir, 'platformatic')
62
+ const files = await walk(baseProjectDir)
63
+ console.log('==> created files', files)
64
+ equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
65
+ equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
66
+ equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
67
+ equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
68
+ equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
69
+
70
+ // Here check the generated service
71
+ const services = await getServices(join(baseProjectDir, 'services'))
72
+ equal(services.length, 1)
73
+ const baseServiceDir = join(baseProjectDir, 'services', services[0])
74
+ console.log(baseServiceDir)
75
+ equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
76
+ equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
77
+ equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
78
+ equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
79
+ })
80
+
81
+ test('Creates a Platformatic Service with typescript', { timeout }, async (t) => {
82
+ const marketplaceHost = await startMarketplace(t)
83
+ // The actions must match IN ORDER
84
+ const actions = [{
85
+ match: 'What kind of project do you want to create?',
86
+ do: [keys.ENTER] // Application
87
+ }, {
88
+ match: 'Where would you like to create your project?',
89
+ do: [keys.ENTER],
90
+ waitAfter: 8000
91
+ }, {
92
+ match: 'Which kind of project do you want to create?',
93
+ do: [keys.ENTER] // Service
94
+ }, {
95
+ match: 'What is the name of the service?',
96
+ do: [keys.ENTER]
97
+ }, {
98
+ match: 'Do you want to create another service?',
99
+ do: [keys.DOWN, keys.ENTER] // no
100
+ }, {
101
+ // NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
102
+ match: 'Do you want to use TypeScript',
103
+ do: [keys.DOWN, keys.ENTER] // no
104
+ }, {
105
+ match: 'What port do you want to use?',
106
+ do: [keys.ENTER]
107
+ }, {
108
+ match: 'Do you want to init the git repository',
109
+ do: [keys.DOWN, keys.ENTER] // yes
110
+ }]
111
+ await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
112
+
113
+ const baseProjectDir = join(tmpDir, 'platformatic')
114
+ const files = await walk(baseProjectDir)
115
+ console.log('==> created files', files)
116
+ equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
117
+ equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
118
+ equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
119
+ equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
120
+ equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
121
+
122
+ // Here check the generated service
123
+ const services = await getServices(join(baseProjectDir, 'services'))
124
+ equal(services.length, 1)
125
+ const baseServiceDir = join(baseProjectDir, 'services', services[0])
126
+ console.log(baseServiceDir)
127
+ equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
128
+ equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
129
+ equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.ts')), true)
130
+ equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.ts')), true)
131
+ })
132
+
133
+ test('Creates a Platformatic Service in a non empty directory', { timeout, skip: true }, async (t) => {
134
+ const marketplaceHost = await startMarketplace(t)
135
+ const targetDirectory = join(tmpdir(), 'platformatic-service-test')
136
+ // const targetDirectory = '/tmp/tst'
137
+ async function generateServiceFileStructure (dir) {
138
+ const servicesDir = join(dir, 'services')
139
+ await safeMkdir(servicesDir)
140
+
141
+ const serviceDir = join(servicesDir, 'foo')
142
+ await safeMkdir(join(serviceDir, 'plugins'))
143
+ await safeMkdir(join(serviceDir, 'routes'))
144
+
145
+ await writeFile(join(dir, '.env'), 'SAMPLE_ENV=foobar\n')
146
+
147
+ // creates 2 files. root.js will be overwritten
148
+ await writeFile(join(serviceDir, 'routes', 'root.js'), 'console.log(\'hello world\')')
149
+ await writeFile(join(serviceDir, 'routes', 'sample.js'), 'console.log(\'hello world\')')
150
+ }
151
+ // generate a sample file structure
152
+ await generateServiceFileStructure(targetDirectory)
153
+
154
+ test.after(async () => {
155
+ await rm(targetDirectory, { recursive: true })
156
+ })
157
+ // The actions must match IN ORDER
158
+ const actions = [{
159
+ match: 'What kind of project do you want to create?',
160
+ do: [keys.ENTER] // Application
161
+ }, {
162
+ match: 'Where would you like to create your project?',
163
+ do: [targetDirectory, keys.ENTER],
164
+ waitAfter: 8000
165
+ }, {
166
+ match: 'Confirm you want to use',
167
+ do: [keys.ENTER] // confirm use existing directory
168
+ }, {
169
+ // NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
170
+ match: 'Do you want to use TypeScript',
171
+ do: [keys.DOWN, keys.ENTER] // no
172
+ }, {
173
+ match: 'What port do you want to use?',
174
+ do: [keys.ENTER]
175
+ }, {
176
+ match: 'Do you want to create the github action to deploy',
177
+ do: [keys.DOWN, keys.ENTER]
178
+ }, {
179
+ match: 'Do you want to enable PR Previews in your application',
180
+ do: [keys.DOWN, keys.ENTER]
181
+ }, {
182
+ match: 'Do you want to init the git repository',
183
+ do: [keys.DOWN, keys.ENTER] // yes
184
+ }]
185
+ await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
186
+
187
+ equal(await isFileAccessible(join(targetDirectory, '.gitignore')), true)
188
+ equal(await isFileAccessible(join(targetDirectory, '.env')), true)
189
+ equal(await isFileAccessible(join(targetDirectory, '.env.sample')), true)
190
+ equal(await isFileAccessible(join(targetDirectory, 'platformatic.service.json')), true)
191
+ equal(await isFileAccessible(join(targetDirectory, 'README.md')), true)
192
+ equal(await isFileAccessible(join(targetDirectory, 'routes', 'root.js')), true)
193
+ equal(await isFileAccessible(join(targetDirectory, 'routes', 'sample.js')), true)
194
+ equal(await isFileAccessible(join(targetDirectory, 'plugins', 'example.js')), true)
195
+ equal(await isFileAccessible(join(targetDirectory, '.git', 'config')), true)
196
+
197
+ // check file contents
198
+ notEqual(await readFile(join(targetDirectory, 'routes', 'root.js'), 'utf8'), 'console.log(\'hello world\')')
199
+ equal(await readFile(join(targetDirectory, 'routes', 'sample.js'), 'utf8'), 'console.log(\'hello world\')')
200
+ })