src/SoFloC.test.ts   A
last analyzed

Complexity

Total Complexity 24
Complexity/F 0

Size

Lines of Code 376
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 24
eloc 317
mnd 24
bc 24
fnc 0
dl 0
loc 376
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
/* eslint-disable @typescript-eslint/no-var-requires */
2
/** global: jest */
3
import { readFileSync } from 'fs'
4
import JSZip, { loadAsync } from 'jszip'
5
import { join } from 'path'
6
import { SoFloC } from '.'
7
import expectedZipCopy from './_jest/expectedZipCopy'
8
import expectedZipDelete from './_jest/expectedZipDelete'
9
import { cleanLineBreak, zipBack } from './_jest/helpers'
10
const crypto = require('crypto')
11
12
jest.setTimeout(10 * 60 * 1000)
13
14
describe('SoFloC', () => {
15
  let file: Buffer
16
  const name = 'TestSolution_2_0_0_0.zip'
17
  const path = join(__dirname, '_jest', name)
18
19
  beforeEach(() => {
20
    jest.mock('crypto')
21
    crypto.randomUUID = jest.fn()
22
      .mockReturnValueOnce('01234567-xxxx-yyyy-zzzz-987654321098')
23
      .mockReturnValueOnce('12345678-yyyy-zzzz-xxxx-876543210987')
24
      .mockReturnValueOnce('23456789-zzzz-xxxx-yyyy-765432109876')
25
    file = readFileSync(path)
26
  })
27
  describe('copyFlow', () => {
28
    test('happy path', async () => {
29
      const sofloc = new SoFloC(file, name)
30
      await sofloc.copyFlow('f4910f26-8210-ec11-b6e6-002248842287', 'First Copy Flow', '2.1.0.0')
31
      await sofloc.copyFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', 'Second Copy Flow')
32
      await sofloc.copyFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', 'Third Copy Flow')
33
34
      const zip = await loadAsync(sofloc.data, { base64: true })
35
      expect(zip.files).toMatchObject(expectedZipCopy)
36
37
      expect(sofloc.name).toEqual('TestSolution_2_1_0_0.zip')
38
      expect(sofloc.version).toEqual('2.1.0.0')
39
40
      for (const key in zip.files) {
41
        if (Object.prototype.hasOwnProperty.call(zip.files, key)) {
42
          if (key !== 'Workflows/') {
43
            const file = zip.files[key]
44
            const data = await file.async('string')
45
46
            const expectedData = readFileSync(join(__dirname, '_jest', 'unzipedCopy', key)).toString()
47
            expect(cleanLineBreak(data)).toEqual(cleanLineBreak(expectedData))
48
          }
49
        }
50
      }
51
52
      expect(sofloc.workflows).toEqual([
53
        { id: '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', name: 'First Test Flow' },
54
        { id: '23456789-zzzz-xxxx-yyyy-765432109876', name: 'Third Copy Flow' },
55
        { id: '12345678-yyyy-zzzz-xxxx-876543210987', name: 'Second Copy Flow' },
56
        { id: 'f4910f26-8210-ec11-b6e6-002248842287', name: 'Second Test Flow' },
57
        { id: '01234567-xxxx-yyyy-zzzz-987654321098', name: 'First Copy Flow' },
58
      ])
59
    })
60
    test('failed to load', async () => {
61
      const sofloc = new SoFloC(null as any, null as any)
62
      let err: any
63
64
      try {
65
        await sofloc.copyFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', 'First Copy Flow')
66
      } catch (error) {
67
        err = error
68
      }
69
      expect(err.message).toBe('Failed to unzip the file')
70
    })
71
    test('Workflow not on the solution', async () => {
72
      const zip = await loadAsync(file, { base64: true })
73
      delete zip.files['Workflows/FirstTestFlow-0F48CBA9-EF0C-ED11-82E4-000D3A64F6F2.json']
74
75
      const data = await zipBack(zip)
76
77
      const sofloc = new SoFloC(data, name)
78
79
      let err: any
80
      try {
81
        await sofloc.copyFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', 'First Copy Flow')
82
      } catch (error) {
83
        err = error
84
      }
85
      expect(err.message).toBe("Workflow file with GUID '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2' does not exist in this Solution or the Solution was changed without updating 'solution.xml' or 'customizations.xml'")
86
    })
87
    test('GUID not found on solution.xml', async () => {
88
      const zip = await loadAsync(file, { base64: true })
89
      let solution = await zip.files['solution.xml'].async('string')
90
      solution = solution.replace('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', '000000000-aaaa-bbbb-cccc-000000000000')
91
      zip.file('solution.xml', solution)
92
93
      const data = await zipBack(zip)
94
95
      const sofloc = new SoFloC(data, name)
96
97
      let err: any
98
      try {
99
        await sofloc.copyFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', 'First Copy Flow')
100
      } catch (error) {
101
        err = error
102
      }
103
      expect(err.message).toBe("Workflow file with GUID '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2' does not exist in this Solution or the Solution was changed without updating 'solution.xml' or 'customizations.xml'")
104
    })
105
    test('GUID not found on customizations.xml', async () => {
106
      const zip = await loadAsync(file, { base64: true })
107
      let customisations = await zip.files['customizations.xml'].async('string')
108
      customisations = customisations.replace('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', '000000000-aaaa-bbbb-cccc-000000000000')
109
      zip.file('customizations.xml', customisations)
110
111
      const data = await zipBack(zip)
112
113
      const sofloc = new SoFloC(data, name)
114
115
      let err: any
116
      try {
117
        await sofloc.copyFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', 'First Copy Flow')
118
      } catch (error) {
119
        err = error
120
      }
121
      expect(err.message).toBe("Workflow file with GUID '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2' does not exist in this Solution or the Solution was changed without updating 'solution.xml' or 'customizations.xml'")
122
    })
123
  })
124
  describe('deleteFlow', () => {
125
    test('happy path', async () => {
126
      const sofloc = new SoFloC(file, name)
127
      await sofloc.deleteFlow('f4910f26-8210-ec11-b6e6-002248842287')
128
129
      const zip = await loadAsync(sofloc.data, { base64: true })
130
      expect(zip.files).toMatchObject(expectedZipDelete)
131
132
      expect(sofloc.name).toEqual('TestSolution_2_0_0_0.zip')
133
      expect(sofloc.version).toEqual('2.0.0.0')
134
135
      for (const key in zip.files) {
136
        if (Object.prototype.hasOwnProperty.call(zip.files, key)) {
137
          if (key !== 'Workflows/') {
138
            const file = zip.files[key]
139
            const data = await file.async('string')
140
141
            const expectedData = readFileSync(join(__dirname, '_jest', 'unzipedDelete', key)).toString()
142
            expect(cleanLineBreak(data)).toEqual(cleanLineBreak(expectedData))
143
          }
144
        }
145
      }
146
147
      expect(sofloc.workflows).toEqual([
148
        { id: '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', name: 'First Test Flow' },
149
      ])
150
    })
151
    test('failed to load', async () => {
152
      const sofloc = new SoFloC(null as any, null as any)
153
      let err: any
154
155
      try {
156
        await sofloc.deleteFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2')
157
      } catch (error) {
158
        err = error
159
      }
160
      expect(err.message).toBe('Failed to unzip the file')
161
    })
162
    test('Workflow not on the solution', async () => {
163
      const zip = await loadAsync(file, { base64: true })
164
      delete zip.files['Workflows/FirstTestFlow-0F48CBA9-EF0C-ED11-82E4-000D3A64F6F2.json']
165
166
      const data = await zipBack(zip)
167
168
      const sofloc = new SoFloC(data, name)
169
170
      let err: any
171
      try {
172
        await sofloc.deleteFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2')
173
      } catch (error) {
174
        err = error
175
      }
176
      expect(err.message).toBe("Workflow file with GUID '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2' does not exist in this Solution or the Solution was changed without updating 'solution.xml' or 'customizations.xml'")
177
    })
178
    test('GUID not found on solution.xml', async () => {
179
      const zip = await loadAsync(file, { base64: true })
180
      let solution = await zip.files['solution.xml'].async('string')
181
      solution = solution.replace('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', '000000000-aaaa-bbbb-cccc-000000000000')
182
      zip.file('solution.xml', solution)
183
184
      const data = await zipBack(zip)
185
186
      const sofloc = new SoFloC(data, name)
187
188
      let err: any
189
      try {
190
        await sofloc.deleteFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2')
191
      } catch (error) {
192
        err = error
193
      }
194
      expect(err.message).toBe("Workflow file with GUID '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2' does not exist in this Solution or the Solution was changed without updating 'solution.xml' or 'customizations.xml'")
195
    })
196
    test('GUID not found on customizations.xml', async () => {
197
      const zip = await loadAsync(file, { base64: true })
198
      let customisations = await zip.files['customizations.xml'].async('string')
199
      customisations = customisations.replace('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', '000000000-aaaa-bbbb-cccc-000000000000')
200
      zip.file('customizations.xml', customisations)
201
202
      const data = await zipBack(zip)
203
204
      const sofloc = new SoFloC(data, name)
205
206
      let err: any
207
      try {
208
        await sofloc.deleteFlow('0f48cba9-ef0c-ed11-82e4-000d3a64f6f2')
209
      } catch (error) {
210
        err = error
211
      }
212
      expect(err.message).toBe("Workflow file with GUID '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2' does not exist in this Solution or the Solution was changed without updating 'solution.xml' or 'customizations.xml'")
213
    })
214
  })
215
  describe('updateVersion', () => {
216
    test('invalid version', async () => {
217
      const sofloc = new SoFloC(file, name)
218
219
      let err: any
220
      try {
221
        await sofloc.updateVersion('1.7.')
222
      } catch (error) {
223
        err = error
224
      }
225
      expect(err.message).toBe('Version \'1.7.\' is not valid. It should follow the format <major>.<minor>.<?build>.<?revision>.')
226
      expect(sofloc.version).toBe('2.0.0.0')
227
    })
228
    test('smaller version', async () => {
229
      const sofloc = new SoFloC(file, name)
230
231
      let err: any
232
      try {
233
        await sofloc.updateVersion('1.99.99.99')
234
      } catch (error) {
235
        err = error
236
      }
237
      expect(err.message).toBe('Version \'1.99.99.99\' is smaller than \'2.0.0.0\'')
238
      expect(sofloc.version).toBe('2.0.0.0')
239
    })
240
    test('smaller version with less chars', async () => {
241
      const sofloc = new SoFloC(file, name)
242
243
      let err: any
244
      try {
245
        await sofloc.updateVersion('1.9')
246
      } catch (error) {
247
        err = error
248
      }
249
      expect(err.message).toBe('Version \'1.9\' is smaller than \'2.0.0.0\'')
250
      expect(sofloc.version).toBe('2.0.0.0')
251
    })
252
    test('bigger version with less chars', async () => {
253
      const sofloc = new SoFloC(file, name)
254
255
      let err: any
256
      try {
257
        await sofloc.updateVersion('2.1')
258
      } catch (error) {
259
        err = error
260
      }
261
      expect(err).toBeUndefined()
262
      expect(sofloc.version).toBe('2.1')
263
    })
264
    test('same version with less chars', async () => {
265
      const sofloc = new SoFloC(file, name)
266
267
      let err: any
268
      try {
269
        await sofloc.updateVersion('2.0')
270
      } catch (error) {
271
        err = error
272
      }
273
      expect(sofloc.version).toBe('2.0.0.0')
274
      expect(err.message).toBe('Version \'2.0\' is smaller than \'2.0.0.0\'')
275
    })
276
    test('same version', async () => {
277
      const sofloc = new SoFloC(file, name)
278
279
      let err: any
280
      try {
281
        await sofloc.updateVersion('2.0.0.0')
282
      } catch (error) {
283
        err = error
284
      }
285
      expect(err).toBeUndefined()
286
      expect(sofloc.version).toBe('2.0.0.0')
287
    })
288
    test('bigger version then smaller, but bigger than original', async () => {
289
      const sofloc = new SoFloC(file, name)
290
291
      let err: any
292
      try {
293
        await sofloc.updateVersion('2.3')
294
        await sofloc.updateVersion('2.1.0.0')
295
      } catch (error) {
296
        err = error
297
      }
298
      expect(err).toBeUndefined()
299
      expect(sofloc.version).toBe('2.1.0.0')
300
    })
301
  })
302
  describe('get workflows', () => {
303
    test('not loaded', async () => {
304
      const sofloc = new SoFloC(file, name)
305
306
      const wfs = sofloc.workflows
307
      expect(wfs).toEqual([])
308
    })
309
  })
310
  describe('data', () => {
311
    test('version is updated', async () => {
312
      const sofloc = new SoFloC(file, name)
313
      await sofloc.updateVersion('2.1.0.0')
314
315
      const zip = await JSZip.loadAsync(sofloc.data, { base64: true })
316
      const solution = await zip.files['solution.xml'].async('string')
317
      const version = solution.match(/<Version>(.*)<\/Version>/) as any[]
318
319
      expect(version[1]).toBe('2.1.0.0')
320
      expect(sofloc.workflows).toEqual([
321
        { id: '0f48cba9-ef0c-ed11-82e4-000d3a64f6f2', name: 'First Test Flow' },
322
        { id: 'f4910f26-8210-ec11-b6e6-002248842287', name: 'Second Test Flow' },
323
      ])
324
    })
325
  })
326
  describe('#load', () => {
327
    test('version not found on Solution)', async () => {
328
      const zip = await loadAsync(file, { base64: true })
329
      let solution = await zip.files['solution.xml'].async('string')
330
      solution = solution.replace('<Version>2.0.0.0</Version>', '')
331
      zip.file('solution.xml', solution)
332
333
      const data = await zipBack(zip)
334
      const sofloc = new SoFloC(data, name)
335
336
      let err: any
337
      try {
338
        await sofloc.updateVersion('2.1.0.0')
339
      } catch (error) {
340
        err = error
341
      }
342
      expect(err.message).toBe('Failed to retrieve the version')
343
    })
344
    test('solution.xml not found', async () => {
345
      const zip = await loadAsync(file, { base64: true })
346
      delete zip.files['solution.xml']
347
348
      const data = await zipBack(zip)
349
      const sofloc = new SoFloC(data, name)
350
351
      let err: any
352
      try {
353
        await sofloc.updateVersion('2.1.0.0')
354
      } catch (error) {
355
        err = error
356
      }
357
      expect(err.message).toBe("'solution.xml' was not found in the Solution zip")
358
    })
359
    test('customizations.xml not found', async () => {
360
      const zip = await loadAsync(file, { base64: true })
361
      delete zip.files['customizations.xml']
362
363
      const data = await zipBack(zip)
364
      const sofloc = new SoFloC(data, name)
365
366
      let err: any
367
      try {
368
        await sofloc.updateVersion('2.1.0.0')
369
      } catch (error) {
370
        err = error
371
      }
372
      expect(err.message).toBe("'customizations.xml' was not found in the Solution zip")
373
    })
374
  })
375
})
376