storyblok 3.17.2 → 3.19.0

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/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
 
6
6
  [![npm](https://img.shields.io/npm/v/storyblok.svg)](https://www.npmjs.com/package/storyblok)
7
7
  [![npm](https://img.shields.io/npm/dt/storyblok.svg)](ttps://img.shields.io/npm/dt/storyblok.svg)
8
- [![GitHub issues](https://img.shields.io/github/issues/storyblok/storyblok.svg?style=flat-square&v=1)](https://github.com/storyblok/storyblok/issues?q=is%3Aopen+is%3Aissue)
9
- [![GitHub closed issues](https://img.shields.io/github/issues-closed/storyblok/storyblok.svg?style=flat-square&v=1)](https://github.com/storyblok/storyblok/issues?q=is%3Aissue+is%3Aclosed)
8
+ [![GitHub issues](https://img.shields.io/github/issues/storyblok/storyblok-cli.svg?style=flat-square&v=1)](https://github.com/storyblok/storyblok/issues?q=is%3Aopen+is%3Aissue)
9
+ [![GitHub closed issues](https://img.shields.io/github/issues-closed/storyblok/storyblok-cli.svg?style=flat-square&v=1)](https://github.com/storyblok/storyblok-cli/issues?q=is%3Aissue+is%3Aclosed)
10
10
 
11
11
  ## BREAKING CHANGE
12
12
 
@@ -22,6 +22,50 @@ $ npm i storyblok -g
22
22
 
23
23
  ## Commands
24
24
 
25
+
26
+ ### login
27
+
28
+ Login to the Storyblok cli
29
+
30
+ ```sh
31
+ $ storyblok login
32
+ ```
33
+ #### Login options
34
+
35
+ ##### Options for Login with email and password
36
+ * `email`: your user's email address
37
+ * `password`: your user's password
38
+
39
+ ##### Options for Login with token (Recomended to SSO user's but works with all user accounts)
40
+ * `token`: your access token
41
+
42
+ **For Both login options you nedd to pass the region**
43
+
44
+ * `region`: your user's region (default: `eu`). You can use `us`, `cn` or `eu`. This region will be used for the other cli's commands.
45
+
46
+ #### Login with token flag
47
+ You can also add the token directly from the login’s command, like the example below:
48
+
49
+ ```sh
50
+ $ storyblok login --token <YOUR_OUTH_TOKEN> --region eu
51
+ ```
52
+
53
+ ### logout
54
+
55
+ Logout from the Storyblok cli
56
+
57
+ ```sh
58
+ $ storyblok logout
59
+ ```
60
+ ### user
61
+
62
+ Get the currently logged in user
63
+
64
+ ```sh
65
+ $ storyblok user
66
+ ```
67
+
68
+
25
69
  ### select
26
70
 
27
71
  Usage to kickstart a boilerplate, fieldtype or theme
@@ -44,27 +88,33 @@ $ storyblok pull-languages --space <SPACE_ID>
44
88
 
45
89
  ### pull-components
46
90
 
47
- Download your space's components schema as json. This command will download 2 files: 1 for the components and 1 for the presets.
91
+ Download your space's components schema as json. By default this command will download 2 files: 1 for the components and 1 for the presets; But if you pass a flag `--separate-files or --sf` the command will create file for each component and presets. And also you could pass a path `--path or -p` to save your components and presets.
92
+
93
+ ```sh
94
+ $ storyblok pull-components --space <SPACE_ID> # Will save files like components-1234.json
95
+ ```
48
96
 
49
97
  ```sh
50
- $ storyblok pull-components --space <SPACE_ID> --region <REGION>
98
+ $ storyblok pull-components --space <SPACE_ID> --separate-files # Will save files like feature-1234.json grid-1234.json
51
99
  ```
52
100
 
53
101
  #### Options
54
102
 
55
103
  * `space`: your space id
104
+ * `separate-files`: boolean flag to save components and presets in single files instead a file with all
105
+ * `path`: the path to save your components and preset files
56
106
 
57
107
  ### push-components
58
108
 
59
109
  Push your components file to your/another space
60
110
 
61
111
  ```sh
62
- $ storyblok push-components <SOURCE> --space <SPACE_ID> --region <REGION> --presets-source <PRESETS_SOURCE>
112
+ $ storyblok push-components <SOURCE> --space <SPACE_ID> --presets-source <PRESETS_SOURCE>
63
113
  ```
64
114
 
65
115
  #### Parameters
66
116
 
67
- * `source`: can be a URL or path to JSON file.
117
+ * `source`: can be a URL or path to JSON file, the path to a json file could be to a single or multiple files separated by comma, like `./pages-1234.json,../User/components/grid-1234.json`
68
118
 
69
119
  Using an **URL**
70
120
 
@@ -72,12 +122,18 @@ Using an **URL**
72
122
  $ storyblok push-components https://raw.githubusercontent.com/storyblok/nuxtdoc/master/seed.components.json --space 67819
73
123
  ```
74
124
 
75
- Using a **path** to file
125
+ Using a **path** to a single file
76
126
 
77
127
  ```sh
78
128
  $ storyblok push-components ./components.json --space 67819
79
129
  ```
80
130
 
131
+ Using a **path** to a multiple files
132
+
133
+ ```sh
134
+ $ storyblok push-components ./page.json,../grid.json,./feature.json --space 67819
135
+ ```
136
+
81
137
  #### Options
82
138
 
83
139
  * `space`: your space id
@@ -188,35 +244,6 @@ Create a space in Storyblok and select the boilerplate to use
188
244
  $ storyblok quickstart
189
245
  ```
190
246
 
191
- ### logout
192
-
193
- Logout from the Storyblok cli
194
-
195
- ```sh
196
- $ storyblok logout
197
- ```
198
-
199
- ### login
200
-
201
- Login to the Storyblok cli
202
-
203
- ```sh
204
- $ storyblok login
205
- ```
206
- #### Options
207
-
208
- * `email`: your user's email address
209
- * `password`: your user's password
210
- * `region`: your user's region (default: `eu`). You can use `us`, `cn` or `eu`. This region will be used for the other cli's commands.
211
-
212
- ### user
213
-
214
- Get the currently logged in user
215
-
216
- ```sh
217
- $ storyblok user
218
- ```
219
-
220
247
  ### generate-migration
221
248
 
222
249
  Create a migration file (with the name `change_<COMPONENT>_<FIELD>.js`) inside the `migrations` folder. Check **Migrations** section to more details
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyblok",
3
- "version": "3.17.2",
3
+ "version": "3.19.0",
4
4
  "description": "A simple CLI to start Storyblok from your command line.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/cli.js CHANGED
@@ -39,14 +39,18 @@ program
39
39
  program
40
40
  .command(COMMANDS.LOGIN)
41
41
  .description('Login to the Storyblok cli')
42
+ .option('-t, --token <token>', 'Token to login directly without questions, like for CI enviroments')
43
+ .option('-r, --region <region>', 'Region of the user')
42
44
  .action(async (options) => {
45
+ const { token, region } = options
46
+
43
47
  if (api.isAuthorized()) {
44
48
  console.log(chalk.green('✓') + ' The user has been already logged. If you want to change the logged user, you must logout and login again')
45
49
  return
46
50
  }
47
51
 
48
52
  try {
49
- await api.processLogin()
53
+ await api.processLogin(token, region)
50
54
  process.exit(0)
51
55
  } catch (e) {
52
56
  console.log(chalk.red('X') + ' An error occurred when logging the user: ' + e.message)
@@ -115,10 +119,13 @@ program
115
119
  // pull-components
116
120
  program
117
121
  .command(COMMANDS.PULL_COMPONENTS)
122
+ .option('--sf, --separate-files [value]', 'Argument to create a single file for each component')
123
+ .option('-p, --path <path>', 'Path to save the component files')
118
124
  .description("Download your space's components schema as json")
119
- .action(async () => {
125
+ .action(async (options) => {
120
126
  console.log(`${chalk.blue('-')} Executing pull-components task`)
121
127
  const space = program.space
128
+ const { separateFiles, path } = options
122
129
  if (!space) {
123
130
  console.log(chalk.red('X') + ' Please provide the space as argument --space YOUR_SPACE_ID.')
124
131
  process.exit(0)
@@ -130,7 +137,7 @@ program
130
137
  }
131
138
 
132
139
  api.setSpaceId(space)
133
- await tasks.pullComponents(api, { space })
140
+ await tasks.pullComponents(api, { space, separateFiles, path })
134
141
  } catch (e) {
135
142
  errorHandler(e, COMMANDS.PULL_COMPONENTS)
136
143
  }
@@ -1,5 +1,5 @@
1
- const fs = require('fs')
2
1
  const chalk = require('chalk')
2
+ const saveFileFactory = require('../utils/save-file-factory')
3
3
 
4
4
  /**
5
5
  * @method getNameFromComponentGroups
@@ -20,11 +20,11 @@ const getNameFromComponentGroups = (groups, uuid) => {
20
20
  /**
21
21
  * @method pullComponents
22
22
  * @param {Object} api
23
- * @param {Object} options { space: Number }
23
+ * @param {Object} options { space: Number, separateFiles: Boolean, path: String }
24
24
  * @return {Promise<Object>}
25
25
  */
26
26
  const pullComponents = async (api, options) => {
27
- const { space } = options
27
+ const { space, separateFiles, path } = options
28
28
 
29
29
  try {
30
30
  const componentGroups = await api.getComponentGroups()
@@ -41,33 +41,40 @@ const pullComponents = async (api, options) => {
41
41
  }
42
42
  })
43
43
 
44
+ if (separateFiles) {
45
+ for (const comp in components) {
46
+ const compFileName = `${components[comp].name}-${space}.json`
47
+ const data = JSON.stringify(components[comp], null, 2)
48
+ saveFileFactory(compFileName, data, path)
49
+ }
50
+ console.log(`${chalk.green('✓')} We've saved your components in files with the names of each component`)
51
+
52
+ if (presets.length === 0) return
53
+
54
+ for (const preset in presets) {
55
+ const presetFileName = `${presets[preset].name}-${space}.json`
56
+ const data = JSON.stringify(presets[preset], null, 2)
57
+ saveFileFactory(presetFileName, data, path)
58
+ }
59
+ console.log(`${chalk.green('✓')} We've saved your presets in files with the names of each preset`)
60
+ return
61
+ }
62
+
44
63
  const file = `components.${space}.json`
45
64
  const data = JSON.stringify({ components }, null, 2)
46
65
 
47
66
  console.log(`${chalk.green('✓')} We've saved your components in the file: ${file}`)
48
67
 
49
- fs.writeFile(`./${file}`, data, err => {
50
- if (err) {
51
- Promise.reject(err)
52
- return
53
- }
68
+ saveFileFactory(file, data, path)
54
69
 
55
- Promise.resolve(file)
56
- })
70
+ if (presets.length === 0) return
57
71
 
58
72
  const presetsFile = `presets.${space}.json`
59
73
  const presetsData = JSON.stringify({ presets }, null, 2)
60
74
 
61
75
  console.log(`${chalk.green('✓')} We've saved your presets in the file: ${presetsFile}`)
62
76
 
63
- fs.writeFile(`./${presetsFile}`, presetsData, err => {
64
- if (err) {
65
- Promise.reject(err)
66
- return
67
- }
68
-
69
- Promise.resolve(presetsFile)
70
- })
77
+ saveFileFactory(presetsFile, presetsData, path)
71
78
  } catch (e) {
72
79
  console.error(`${chalk.red('X')} An error ocurred in pull-components task when load components data`)
73
80
  return Promise.reject(new Error(e))
@@ -21,30 +21,53 @@ const getGroupByUuid = (groups, uuid) => {
21
21
 
22
22
  /**
23
23
  * Get the data from a local or remote JSON file
24
- * @param {string} source the local path or remote url of the file
24
+ * @param {string} path the local path or remote url of the file
25
25
  * @returns {Promise<Object>} return the data from the source or an error
26
26
  */
27
- const getDataFromSource = async (source) => {
28
- if (!source) {
27
+ const getDataFromPath = async (path) => {
28
+ if (!path) {
29
29
  return {}
30
30
  }
31
+ const sources = path.split(',')
32
+ const isList = sources.length > 1
31
33
 
32
34
  try {
33
- if (isUrl(source)) {
34
- return (await axios.get(source)).data
35
+ if (isUrl(path)) {
36
+ return (await axios.get(path)).data
35
37
  } else {
36
- return JSON.parse(fs.readFileSync(source, 'utf8'))
38
+ if (!isList) return JSON.parse(fs.readFileSync(sources[0], 'utf8'))
39
+
40
+ const data = []
41
+ sources.forEach((source) => {
42
+ data.push(JSON.parse(fs.readFileSync(source, 'utf8')))
43
+ })
44
+ return data
37
45
  }
38
46
  } catch (err) {
39
- console.error(`${chalk.red('X')} Can not load json file from ${source}`)
47
+ console.error(`${chalk.red('X')} Can not load json file from ${path}`)
40
48
  return Promise.reject(err)
41
49
  }
42
50
  }
43
51
 
52
+ /**
53
+ * Creat an array based in the content parameter and the key provided
54
+ * @param {object} content the data to create a list
55
+ * @param {string} key key to serch in the content
56
+ * @returns {Array} return the data from the source or an error
57
+ */
58
+ const createContentList = (content, key) => {
59
+ if (content[key]) return content[key]
60
+ else if (Array.isArray(content)) return [...content]
61
+ else return [content]
62
+ }
63
+
44
64
  module.exports = async (api, { source, presetsSource }) => {
45
65
  try {
46
- const components = (await getDataFromSource(source)).components || []
47
- const presets = (await getDataFromSource(presetsSource)).presets || []
66
+ const rawComponents = await getDataFromPath(source)
67
+ const components = createContentList(rawComponents, 'components')
68
+ const rawPresets = await getDataFromPath(presetsSource)
69
+ const presets = createContentList(rawPresets, 'presets')
70
+
48
71
  return push(api, components, presets)
49
72
  } catch (err) {
50
73
  console.error(`${chalk.red('X')} Can not push invalid json - please provide a valid json file`)
package/src/utils/api.js CHANGED
@@ -35,7 +35,8 @@ module.exports = {
35
35
  return path
36
36
  },
37
37
 
38
- async login (email, password, region) {
38
+ async login (content) {
39
+ const { email, password, region } = content
39
40
  try {
40
41
  const response = await axios.post(`${this.apiSwitcher(region)}users/login`, {
41
42
  email: email,
@@ -68,10 +69,10 @@ module.exports = {
68
69
  otp_attempt: code
69
70
  })
70
71
 
71
- return this.persistCredentials(email, newResponse.data || {}, region)
72
+ return this.persistCredentials(email, newResponse.data.access_token || {}, region)
72
73
  }
73
74
 
74
- return this.persistCredentials(email, data, region)
75
+ return this.persistCredentials(email, data.access_token, region)
75
76
  } catch (e) {
76
77
  return Promise.reject(e)
77
78
  }
@@ -92,27 +93,43 @@ module.exports = {
92
93
  }
93
94
  },
94
95
 
95
- persistCredentials (email, data, region = 'eu') {
96
- const token = this.extractToken(data)
96
+ persistCredentials (email, token = null, region = 'eu') {
97
97
  if (token) {
98
98
  this.oauthToken = token
99
99
  creds.set(email, token, region)
100
100
 
101
- return Promise.resolve(data)
101
+ return Promise.resolve(token)
102
102
  }
103
103
  return Promise.reject(new Error('The code could not be authenticated.'))
104
104
  },
105
105
 
106
- async processLogin () {
106
+ async processLogin (token = null, region = null) {
107
107
  try {
108
- const questions = getQuestions('login')
109
- const { email, password, region } = await inquirer.prompt(questions)
108
+ if (token && region) {
109
+ await this.loginWithToken({ token, region })
110
+ console.log(chalk.green('✓') + ' Log in successfully! Token has been added to .netrc file.')
111
+ return Promise.resolve({ token, region })
112
+ }
110
113
 
111
- const data = await this.login(email, password, region)
114
+ let content = {}
115
+ await inquirer
116
+ .prompt(getQuestions('login-strategy'))
117
+ .then(async ({ strategy }) => {
118
+ content = await inquirer.prompt(getQuestions(strategy))
119
+ })
120
+ .catch((error) => {
121
+ console.log(error)
122
+ })
123
+
124
+ if (!content.token) {
125
+ await this.login(content)
126
+ } else {
127
+ await this.loginWithToken(content)
128
+ }
112
129
 
113
130
  console.log(chalk.green('✓') + ' Log in successfully! Token has been added to .netrc file.')
114
131
 
115
- return Promise.resolve(data)
132
+ return Promise.resolve(content)
116
133
  } catch (e) {
117
134
  if (e.response && e.response.data && e.response.data.error) {
118
135
  console.error(chalk.red('X') + ' An error ocurred when login the user: ' + e.response.data.error)
@@ -125,8 +142,20 @@ module.exports = {
125
142
  }
126
143
  },
127
144
 
128
- extractToken (data) {
129
- return data.access_token
145
+ async loginWithToken (content) {
146
+ const { token, region } = content
147
+ try {
148
+ const { data } = await axios.get(`${this.apiSwitcher(region)}users/me`, {
149
+ headers: {
150
+ Authorization: token
151
+ }
152
+ })
153
+
154
+ this.persistCredentials(data.user.email, token, region)
155
+ return data.user
156
+ } catch (e) {
157
+ return Promise.reject(e)
158
+ }
130
159
  },
131
160
 
132
161
  logout (unauthorized) {
@@ -1,5 +1,24 @@
1
1
  const getOptions = (subCommand, argv = {}, api = {}) => {
2
2
  let email = ''
3
+ const moreOptions = [
4
+ 'delete-templates',
5
+ 'pull-components',
6
+ 'push-components',
7
+ 'scaffold'
8
+ ]
9
+ const regionInput = {
10
+ type: 'input',
11
+ name: 'region',
12
+ message: 'Enter your user\'s region (us, eu or cn):',
13
+ validate: function (value) {
14
+ const flagList = ['us', 'cn', 'eu']
15
+ if (flagList.indexOf(value) > -1) {
16
+ return true
17
+ }
18
+
19
+ return 'Please enter a valid region: us, eu or cn'
20
+ }
21
+ }
3
22
 
4
23
  if (subCommand === 'select') {
5
24
  return [
@@ -103,7 +122,29 @@ const getOptions = (subCommand, argv = {}, api = {}) => {
103
122
  ]
104
123
  }
105
124
 
106
- if (subCommand === 'login') {
125
+ if (subCommand === 'login-strategy') {
126
+ return [
127
+ {
128
+ type: 'list',
129
+ name: 'strategy',
130
+ message: 'Select the login strategy: ',
131
+ choices: [
132
+ {
133
+ name: 'With email and password (Common users with storyblok account)',
134
+ value: 'login-with-email',
135
+ short: 'Email'
136
+ },
137
+ {
138
+ name: 'With Token (Most recommended for SSO users)',
139
+ value: 'login-with-token',
140
+ short: 'Token'
141
+ }
142
+ ]
143
+ }
144
+ ]
145
+ }
146
+
147
+ if (subCommand === 'login-with-email') {
107
148
  return [
108
149
  {
109
150
  type: 'input',
@@ -129,29 +170,27 @@ const getOptions = (subCommand, argv = {}, api = {}) => {
129
170
  return 'Please enter a valid password:'
130
171
  }
131
172
  },
173
+ regionInput
174
+ ]
175
+ }
176
+
177
+ if (subCommand === 'login-with-token') {
178
+ return [
132
179
  {
133
180
  type: 'input',
134
- name: 'region',
135
- message: 'Enter your user\'s region (us, eu or cn):',
181
+ name: 'token',
182
+ message: 'Enter your token:',
136
183
  validate: function (value) {
137
- const flagList = ['us', 'cn', 'eu']
138
- if (flagList.indexOf(value) > -1) {
184
+ if (value.length > 0) {
139
185
  return true
140
186
  }
141
-
142
- return 'Please enter a valid region: us, eu or cn'
187
+ return 'Please enter a valid token:'
143
188
  }
144
- }
189
+ },
190
+ regionInput
145
191
  ]
146
192
  }
147
193
 
148
- const moreOptions = [
149
- 'delete-templates',
150
- 'pull-components',
151
- 'push-components',
152
- 'scaffold'
153
- ]
154
-
155
194
  if (moreOptions.indexOf(subCommand) > -1) {
156
195
  const loginQuestions = [
157
196
  {
@@ -5,5 +5,6 @@ module.exports = {
5
5
  creds: require('./creds'),
6
6
  capitalize: require('./capitalize'),
7
7
  findByProperty: require('./find-by-property'),
8
- parseError: require('./parse-error')
8
+ parseError: require('./parse-error'),
9
+ saveFileFactory: require('./save-file-factory')
9
10
  }
@@ -0,0 +1,16 @@
1
+ const fs = require('fs')
2
+
3
+ const saveFileFactory = async (fileName, content, path = './') => {
4
+ return new Promise((resolve, reject) => {
5
+ fs.writeFile(`${path}${fileName}`, content, err => {
6
+ if (err) {
7
+ Promise.reject(err)
8
+ return
9
+ }
10
+
11
+ Promise.resolve(true)
12
+ })
13
+ })
14
+ }
15
+
16
+ module.exports = saveFileFactory
@@ -3,7 +3,7 @@ const PASSWORD_TEST = 'test'
3
3
  const TOKEN_TEST = 'storyblok1234'
4
4
  const REGION_TEST = 'eu'
5
5
 
6
- // use functions to always returns "new" data
6
+ // use functions to always returns 'new' data
7
7
  const FAKE_COMPONENTS = () => [
8
8
  {
9
9
  name: 'teaser',
@@ -136,7 +136,7 @@ const FAKE_COMPONENTS = () => [
136
136
  }
137
137
  ]
138
138
 
139
- // use functions to always returns "new" data
139
+ // use functions to always returns 'new' data
140
140
  const FAKE_STORIES = () => [
141
141
  {
142
142
  name: 'About',
@@ -249,6 +249,46 @@ const FAKE_SPACE_OPTIONS = () => ({
249
249
  use_translated_stories: false
250
250
  })
251
251
 
252
+ const FAKE_PRESET = () => ({
253
+ id: 123,
254
+ name: 'page_preset',
255
+ preset: {
256
+ _uid: '7dce995b-07ed-4e5b-a4bb-5d22447252d8',
257
+ body: [
258
+ {
259
+ _uid: '995e84c1-a08d-45cd-b121-e4db45e9cf50',
260
+ headline: 'Hello world!',
261
+ component: 'teaser'
262
+ },
263
+ {
264
+ _uid: 'a6e118ec-1a57-4f0f-b1e9-1ed625a82751',
265
+ columns: [
266
+ {
267
+ _uid: '9b0a9bed-e891-4edc-8f5e-bc29e7ec785c',
268
+ name: 'Feature 1',
269
+ component: 'feature'
270
+ },
271
+ {
272
+ _uid: '07863609-7518-48b9-8d28-b1e8037818e2',
273
+ name: 'Feature 2',
274
+ component: 'feature'
275
+ }
276
+ ],
277
+ component: 'grid'
278
+ }
279
+ ],
280
+ component: 'page'
281
+ },
282
+ component_id: 3481284,
283
+ space_id: 200378,
284
+ created_at: '2023-02-24T16:49:14.723Z',
285
+ updated_at: '2023-02-24T16:49:14.723Z',
286
+ image: '',
287
+ color: '',
288
+ icon: '',
289
+ description: 'page preset'
290
+ })
291
+
252
292
  module.exports = {
253
293
  EMAIL_TEST,
254
294
  TOKEN_TEST,
@@ -257,5 +297,6 @@ module.exports = {
257
297
  FAKE_COMPONENTS,
258
298
  FAKE_SPACES,
259
299
  FAKE_SPACE_OPTIONS,
260
- REGION_TEST
300
+ REGION_TEST,
301
+ FAKE_PRESET
261
302
  }
@@ -1,6 +1,6 @@
1
1
  const fs = require('fs')
2
2
  const pullComponents = require('../../src/tasks/pull-components')
3
- const { FAKE_COMPONENTS } = require('../constants')
3
+ const { FAKE_COMPONENTS, FAKE_PRESET } = require('../constants')
4
4
 
5
5
  jest.mock('fs')
6
6
 
@@ -24,36 +24,12 @@ describe('testing pullComponents', () => {
24
24
  })
25
25
  })
26
26
 
27
- it('api.getComponents() should be call fs.writeFile correctly', async () => {
27
+ it('pull components should be call fs.writeFile correctly and generate component file', async () => {
28
28
  const SPACE = 12345
29
- const BODY = {
30
- components: [
31
- {
32
- name: 'teaser',
33
- display_name: null,
34
- created_at: '2019-10-15T17:00:32.212Z',
35
- id: 581153,
36
- schema: {
37
- headline: {
38
- type: 'text'
39
- }
40
- },
41
- image: null,
42
- preview_field: null,
43
- is_root: false,
44
- preview_tmpl: null,
45
- is_nestable: true,
46
- all_presets: [],
47
- preset_id: null,
48
- real_name: 'teaser',
49
- component_group_uuid: null
50
- }
51
- ]
52
- }
53
29
 
54
30
  const api = {
55
31
  getComponents () {
56
- return Promise.resolve(BODY.components)
32
+ return Promise.resolve([FAKE_COMPONENTS()[0]])
57
33
  },
58
34
  getComponentGroups () {
59
35
  return Promise.resolve([])
@@ -73,9 +49,85 @@ describe('testing pullComponents', () => {
73
49
  .then(_ => {
74
50
  const [path, data] = fs.writeFile.mock.calls[0]
75
51
 
76
- expect(fs.writeFile.mock.calls.length).toBe(2)
52
+ expect(fs.writeFile.mock.calls.length).toBe(1)
77
53
  expect(path).toBe(`./${expectFileName}`)
78
- expect(JSON.parse(data)).toEqual(BODY)
54
+ expect(JSON.parse(data)).toEqual({ components: [FAKE_COMPONENTS()[0]] })
55
+ })
56
+ })
57
+
58
+ it('pull components should be call fs.writeFile correctly and generate a component and preset files', async () => {
59
+ const SPACE = 12345
60
+
61
+ const api = {
62
+ getComponents () {
63
+ return Promise.resolve([FAKE_COMPONENTS()[0]])
64
+ },
65
+ getComponentGroups () {
66
+ return Promise.resolve([])
67
+ },
68
+ getPresets () {
69
+ return Promise.resolve(FAKE_PRESET())
70
+ }
71
+ }
72
+
73
+ const options = {
74
+ space: SPACE
75
+ }
76
+
77
+ const expectComponentFileName = `components.${SPACE}.json`
78
+ const expectPresetFileName = `presets.${SPACE}.json`
79
+
80
+ return pullComponents(api, options)
81
+ .then(_ => {
82
+ const [compPath, compData] = fs.writeFile.mock.calls[0]
83
+ const [presetPath, presetData] = fs.writeFile.mock.calls[1]
84
+
85
+ expect(fs.writeFile.mock.calls.length).toBe(2)
86
+
87
+ expect(compPath).toBe(`./${expectComponentFileName}`)
88
+ expect(JSON.parse(compData)).toEqual({ components: [FAKE_COMPONENTS()[0]] })
89
+
90
+ expect(presetPath).toBe(`./${expectPresetFileName}`)
91
+ expect(JSON.parse(presetData)).toEqual({ presets: FAKE_PRESET() })
92
+ })
93
+ })
94
+
95
+ it('pull components should be call fs.writeFile and generate a single file for each component', async () => {
96
+ const SPACE = 12345
97
+
98
+ const api = {
99
+ getComponents () {
100
+ return Promise.resolve(FAKE_COMPONENTS())
101
+ },
102
+ getComponentGroups () {
103
+ return Promise.resolve([])
104
+ },
105
+ getPresets () {
106
+ return Promise.resolve([])
107
+ }
108
+ }
109
+
110
+ const options = {
111
+ space: SPACE,
112
+ separateFiles: true
113
+ }
114
+
115
+ return pullComponents(api, options)
116
+ .then(_ => {
117
+ expect(fs.writeFile.mock.calls.length).toBe(FAKE_COMPONENTS().length)
118
+
119
+ for (const comp in FAKE_COMPONENTS()) {
120
+ const compFileName = `${FAKE_COMPONENTS()[comp].name}-${SPACE}.json`
121
+ let data = FAKE_COMPONENTS()[comp]
122
+ const [compPath, compData] = fs.writeFile.mock.calls[comp]
123
+
124
+ if (FAKE_COMPONENTS()[comp].name === 'logo') {
125
+ data = { ...FAKE_COMPONENTS()[comp], component_group_name: '' }
126
+ }
127
+
128
+ expect(compPath).toBe(`./${compFileName}`)
129
+ expect(JSON.parse(compData)).toEqual(data)
130
+ }
79
131
  })
80
132
  })
81
133
 
@@ -1,6 +1,7 @@
1
1
  const sync = require('../../src/tasks/sync')
2
2
  const PresetsLib = jest.requireActual('../../src/utils/presets-lib')
3
- const { TOKEN_TEST, FAKE_COMPONENTS } = require('../constants')
3
+ const { TOKEN_TEST, EMAIL_TEST, REGION_TEST, FAKE_COMPONENTS } = require('../constants')
4
+ const creds = require('../../src/utils/creds')
4
5
 
5
6
  const FAKE_COMPONENTS_TO_TEST = {
6
7
  '001': {
@@ -217,6 +218,7 @@ const TARGET_SPACE_TEST = '002'
217
218
 
218
219
  describe('testing syncComponents', () => {
219
220
  beforeAll(() => {
221
+ creds.set(EMAIL_TEST, TOKEN_TEST, REGION_TEST)
220
222
  // we need to execute once this function to test it
221
223
  const _types = ['components']
222
224