backstage

Форк
0
/
reader.test.ts 
745 строк · 22.9 Кб
1
/*
2
 * Copyright 2020 The Backstage Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
import { withLogCollector } from '@backstage/test-utils';
18
import { ConfigReader } from './reader';
19

20
const DATA = {
21
  zero: 0,
22
  one: 1,
23
  true: true,
24
  false: false,
25
  yes: 'yes',
26
  no: 'no',
27
  y: 'y',
28
  n: 'n',
29
  on: 'on',
30
  off: 'off',
31
  zeroString: '0',
32
  oneString: '1',
33
  stringFalse: 'false',
34
  null: null,
35
  string: 'string',
36
  emptyString: '',
37
  strings: ['string1', 'string2'],
38
  badStrings: ['string1', ''],
39
  worseStrings: ['string1', 3] as string[],
40
  worstStrings: ['string1', 'string2', {}] as string[],
41
  nested: {
42
    one: 1,
43
    null: null,
44
    string: 'string',
45
    strings: ['string1', 'string2'],
46
  },
47
  nestlings: [{ boolean: true }, { string: 'string' }, { number: 42 }] as {}[],
48
};
49

50
function expectValidValues(config: ConfigReader) {
51
  expect(config.keys()).toEqual(Object.keys(DATA));
52
  expect(config.get('zero')).toBe(0);
53
  expect(config.has('zero')).toBe(true);
54
  expect(config.has('false')).toBe(true);
55
  expect(config.has('null')).toBe(true);
56
  expect(config.has('missing')).toBe(false);
57
  expect(config.has('nested.one')).toBe(true);
58
  expect(config.has('nested.missing')).toBe(false);
59
  expect(config.has('nested.null')).toBe(true);
60
  expect(config.getNumber('zero')).toBe(0);
61
  expect(config.getNumber('one')).toBe(1);
62
  expect(config.getNumber('zeroString')).toBe(0);
63
  expect(config.getNumber('oneString')).toBe(1);
64
  expect(config.getOptional('true')).toBe(true);
65
  expect(config.getBoolean('true')).toBe(true);
66
  expect(config.getBoolean('false')).toBe(false);
67
  expect(config.getBoolean('stringFalse')).toBe(false);
68
  expect(config.getBoolean('zero')).toBe(false);
69
  expect(config.getBoolean('one')).toBe(true);
70
  expect(config.getBoolean('zeroString')).toBe(false);
71
  expect(config.getBoolean('oneString')).toBe(true);
72
  expect(config.getBoolean('yes')).toBe(true);
73
  expect(config.getBoolean('no')).toBe(false);
74
  expect(config.getBoolean('y')).toBe(true);
75
  expect(config.getBoolean('n')).toBe(false);
76
  expect(config.getBoolean('on')).toBe(true);
77
  expect(config.getBoolean('off')).toBe(false);
78
  expect(config.getString('string')).toBe('string');
79
  expect(config.get('strings')).toEqual(['string1', 'string2']);
80
  expect(config.getStringArray('strings')).toEqual(['string1', 'string2']);
81
  expect(config.getConfig('nested').getNumber('one')).toBe(1);
82
  expect(config.get('nested')).toEqual({
83
    one: 1,
84
    null: null,
85
    string: 'string',
86
    strings: ['string1', 'string2'],
87
  });
88
  expect(config.getConfig('nested').getString('string')).toBe('string');
89
  expect(config.getOptionalConfig('nested')!.getStringArray('strings')).toEqual(
90
    ['string1', 'string2'],
91
  );
92
  expect(config.getOptional('missing')).toBe(undefined);
93
  expect(config.getOptionalConfig('missing')).toBe(undefined);
94
  expect(config.getOptionalConfigArray('missing')).toBe(undefined);
95
  expect(config.getNumber('zero')).toBe(0);
96
  expect(config.getBoolean('true')).toBe(true);
97
  expect(config.getString('string')).toBe('string');
98
  expect(config.getStringArray('strings')).toEqual(['string1', 'string2']);
99

100
  const [config1, config2, config3] = config.getConfigArray('nestlings');
101
  expect(config1.getBoolean('boolean')).toBe(true);
102
  expect(config2.getString('string')).toBe('string');
103
  expect(config3.getNumber('number')).toBe(42);
104
  expect(
105
    config.getOptionalConfigArray('nestlings')![0].getBoolean('boolean'),
106
  ).toBe(true);
107
}
108

109
function expectInvalidValues(config: ConfigReader) {
110
  expect(() => config.getBoolean('string')).toThrow(
111
    "Unable to convert config value for key 'string' in 'ctx' to a boolean",
112
  );
113
  expect(() => config.getNumber('string')).toThrow(
114
    "Unable to convert config value for key 'string' in 'ctx' to a number",
115
  );
116
  expect(() => config.getString('one')).toThrow(
117
    "Invalid type in config for key 'one' in 'ctx', got number, wanted string",
118
  );
119
  expect(() => config.getNumber('true')).toThrow(
120
    "Invalid type in config for key 'true' in 'ctx', got boolean, wanted number",
121
  );
122
  expect(() => config.getStringArray('null')).toThrow(
123
    "Invalid type in config for key 'null' in 'ctx', got null, wanted string-array",
124
  );
125
  expect(() => config.getString('emptyString')).toThrow(
126
    "Invalid type in config for key 'emptyString' in 'ctx', got empty-string, wanted string",
127
  );
128
  expect(() => config.getStringArray('badStrings')).toThrow(
129
    "Invalid type in config for key 'badStrings[1]' in 'ctx', got empty-string, wanted string",
130
  );
131
  expect(() => config.getStringArray('worseStrings')).toThrow(
132
    "Invalid type in config for key 'worseStrings[1]' in 'ctx', got number, wanted string",
133
  );
134
  expect(() => config.getStringArray('worstStrings')).toThrow(
135
    "Invalid type in config for key 'worstStrings[2]' in 'ctx', got object, wanted string",
136
  );
137
  expect(() => config.getConfig('one')).toThrow(
138
    "Invalid type in config for key 'one' in 'ctx', got number, wanted object",
139
  );
140
  expect(() => config.getConfigArray('one')).toThrow(
141
    "Invalid type in config for key 'one' in 'ctx', got number, wanted object-array",
142
  );
143
  expect(() => config.getBoolean('missing')).toThrow(
144
    "Missing required config value at 'missing'",
145
  );
146
  expect(() => config.getNumber('missing')).toThrow(
147
    "Missing required config value at 'missing'",
148
  );
149
  expect(() => config.getString('missing')).toThrow(
150
    "Missing required config value at 'missing'",
151
  );
152
  expect(() => config.getStringArray('missing')).toThrow(
153
    "Missing required config value at 'missing'",
154
  );
155
}
156

157
const CTX = 'ctx';
158

159
describe('ConfigReader', () => {
160
  it('should read empty config with valid keys', () => {
161
    const config = new ConfigReader({}, CTX);
162
    expect(config.keys()).toEqual([]);
163
    expect(config.getOptional()).toEqual({});
164
    expect(config.getOptional('x')).toBeUndefined();
165
    expect(config.getOptionalString('x')).toBeUndefined();
166
    expect(config.getOptionalString('x_x')).toBeUndefined();
167
    expect(config.getOptionalString('x-X')).toBeUndefined();
168
    expect(config.getOptionalString('x0')).toBeUndefined();
169
    expect(config.getOptionalString('X-x2')).toBeUndefined();
170
    expect(config.getOptionalString('x0_x0')).toBeUndefined();
171
    expect(config.getOptionalString('x_x-x_x')).toBeUndefined();
172

173
    expect(
174
      new ConfigReader(undefined, CTX).getOptionalString('x'),
175
    ).toBeUndefined();
176
  });
177

178
  it('should throw on invalid keys', () => {
179
    const config = new ConfigReader({}, CTX);
180

181
    expect(() => config.has('.')).toThrow(/^Invalid config key/);
182
    expect(() => config.get('0')).toThrow(/^Invalid config key/);
183
    expect(() => config.getOptional('(')).toThrow(/^Invalid config key/);
184
    expect(() => config.getString('z-_')).toThrow(/^Invalid config key/);
185
    expect(() => config.getOptionalString('-')).toThrow(/^Invalid config key/);
186
    expect(() => config.getNumber('.a')).toThrow(/^Invalid config key/);
187
    expect(() => config.getConfig('0.a')).toThrow(/^Invalid config key/);
188
    expect(() => config.getOptionalConfig('0a')).toThrow(/^Invalid config key/);
189
    expect(() => config.getString('a.0a')).toThrow(/^Invalid config key/);
190
    expect(() => config.getString('a..a')).toThrow(/^Invalid config key/);
191
    expect(() => config.getString('a.')).toThrow(/^Invalid config key/);
192
    expect(() => config.getString('a...')).toThrow(/^Invalid config key/);
193
    expect(() => config.getString('a.a.a.a.')).toThrow(/^Invalid config key/);
194
    expect(() => config.getString('a._')).toThrow(/^Invalid config key/);
195
    expect(() => config.getString('a.-.a')).toThrow(/^Invalid config key/);
196

197
    expect(() => new ConfigReader(undefined, CTX).getString('.')).toThrow(
198
      /^Invalid config key/,
199
    );
200
  });
201

202
  it('should read valid values', () => {
203
    const config = new ConfigReader(DATA, CTX);
204
    expectValidValues(config);
205
  });
206

207
  it('should fail to read invalid values', () => {
208
    const config = new ConfigReader(DATA, CTX);
209
    expectInvalidValues(config);
210
  });
211

212
  it('should warn when accessing filtered keys in development mode', () => {
213
    const oldEnv = process.env.NODE_ENV;
214
    (process.env as any).NODE_ENV = 'development';
215

216
    const config = ConfigReader.fromConfigs([
217
      {
218
        data: DATA,
219
        context: CTX,
220
        filteredKeys: ['a', 'a2', 'b[0]'],
221
      },
222
    ]);
223

224
    expect(withLogCollector(() => config.getOptional('a'))).toMatchObject({
225
      warn: [
226
        "Failed to read configuration value at 'a' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.",
227
      ],
228
    });
229
    expect(
230
      withLogCollector(() => config.getOptionalString('a2')),
231
    ).toMatchObject({
232
      warn: [
233
        "Failed to read configuration value at 'a2' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.",
234
      ],
235
    });
236
    expect(
237
      withLogCollector(() => config.getOptionalConfigArray('b')),
238
    ).toMatchObject({
239
      warn: [
240
        "Failed to read configuration array at 'b' as it does not have any visible elements. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.",
241
      ],
242
    });
243

244
    (process.env as any).NODE_ENV = oldEnv;
245
  });
246

247
  it('only warns once when accessing filtered keys in development mode', () => {
248
    const oldEnv = process.env.NODE_ENV;
249
    (process.env as any).NODE_ENV = 'development';
250

251
    const config = ConfigReader.fromConfigs([
252
      {
253
        data: DATA,
254
        context: CTX,
255
        filteredKeys: ['a'],
256
      },
257
    ]);
258

259
    expect(withLogCollector(() => config.getOptional('a'))).toMatchObject({
260
      warn: [
261
        "Failed to read configuration value at 'a' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.",
262
      ],
263
    });
264
    expect(withLogCollector(() => config.getOptional('a'))).toMatchObject({
265
      warn: [],
266
    });
267

268
    (process.env as any).NODE_ENV = oldEnv;
269
  });
270

271
  it('should not warn when accessing filtered keys outside of development mode', () => {
272
    const config = ConfigReader.fromConfigs([
273
      {
274
        data: DATA,
275
        context: CTX,
276
        filteredKeys: ['a', 'b[0]'],
277
      },
278
    ]);
279

280
    expect(withLogCollector(() => config.getOptional('a'))).toMatchObject({
281
      warn: [],
282
    });
283
    expect(withLogCollector(() => config.getOptionalString('a'))).toMatchObject(
284
      { warn: [] },
285
    );
286
    expect(
287
      withLogCollector(() => config.getOptionalConfigArray('b')),
288
    ).toMatchObject({ warn: [] });
289
  });
290

291
  it('should coerce number strings to numbers', () => {
292
    const config = ConfigReader.fromConfigs([
293
      {
294
        data: {
295
          port: '123',
296
        },
297
        context: '1',
298
      },
299
    ]);
300

301
    expect(config.getNumber('port')).toEqual(123);
302
  });
303
});
304

305
describe('ConfigReader with fallback', () => {
306
  it('should behave as if without fallback', () => {
307
    const config = new ConfigReader({}, CTX, new ConfigReader(DATA, CTX));
308
    expect(config.getOptionalString('x')).toBeUndefined();
309
    expect(() => config.getString('.')).toThrow(/^Invalid config key/);
310
    expect(() => config.getString('a.')).toThrow(/^Invalid config key/);
311
  });
312

313
  it('should read values from itself', () => {
314
    const config = new ConfigReader(DATA, CTX, new ConfigReader({}, CTX));
315
    expectValidValues(config);
316
    expectInvalidValues(config);
317
  });
318

319
  it('should read values from a fallback', () => {
320
    const config = new ConfigReader({}, CTX, new ConfigReader(DATA, CTX));
321
    expectValidValues(config);
322
    expectInvalidValues(config);
323
  });
324

325
  it('should read values from multiple levels of fallbacks', () => {
326
    const config = new ConfigReader(
327
      {},
328
      CTX,
329
      new ConfigReader(
330
        {},
331
        CTX,
332
        new ConfigReader({}, CTX, new ConfigReader(DATA, CTX)),
333
      ),
334
    );
335
    expectValidValues(config);
336
    expectInvalidValues(config);
337
  });
338

339
  it('should show error with correct context', () => {
340
    const config = ConfigReader.fromConfigs([
341
      {
342
        data: {
343
          a: true,
344
          b: true,
345
          c: true,
346
          nested1: {
347
            a: true,
348
            b: true,
349
          },
350
          badBefore: {
351
            a: true,
352
          },
353
          badAfter: true,
354
        },
355
        context: 'z',
356
      },
357
      {
358
        data: {
359
          b: true,
360
          c: true,
361
          nested1: {
362
            a: true,
363
          },
364
          badBefore: true,
365
          badAfter: {
366
            a: true,
367
          },
368
        },
369
        context: 'y',
370
      },
371
      {
372
        data: {
373
          c: true,
374
        },
375
        context: 'x',
376
      },
377
    ]);
378

379
    expect(() => config.getNumber('a')).toThrow(
380
      "Invalid type in config for key 'a' in 'z', got boolean, wanted number",
381
    );
382
    expect(() => config.getNumber('b')).toThrow(
383
      "Invalid type in config for key 'b' in 'y', got boolean, wanted number",
384
    );
385
    expect(() => config.getNumber('c')).toThrow(
386
      "Invalid type in config for key 'c' in 'x', got boolean, wanted number",
387
    );
388
    expect(() => config.getNumber('nested1.a')).toThrow(
389
      "Invalid type in config for key 'nested1.a' in 'y', got boolean, wanted number",
390
    );
391
    expect(() => config.getNumber('nested1.b')).toThrow(
392
      "Invalid type in config for key 'nested1.b' in 'z', got boolean, wanted number",
393
    );
394
    expect(() => config.getConfig('nested1').getNumber('a')).toThrow(
395
      "Invalid type in config for key 'nested1.a' in 'y', got boolean, wanted number",
396
    );
397
    expect(() => config.getConfig('nested1').getNumber('b')).toThrow(
398
      "Invalid type in config for key 'nested1.b' in 'z', got boolean, wanted number",
399
    );
400
    expect(() => config.getNumber('badBefore.a')).toThrow(
401
      "Invalid type in config for key 'badBefore' in 'y', got boolean, wanted object",
402
    );
403
    expect(() => config.getNumber('badBefore.b')).toThrow(
404
      "Invalid type in config for key 'badBefore' in 'y', got boolean, wanted object",
405
    );
406
    expect(() => config.getNumber('badAfter.a')).toThrow(
407
      "Invalid type in config for key 'badAfter.a' in 'y', got boolean, wanted number",
408
    );
409
    expect(() => config.getNumber('badAfter.b')).toThrow(
410
      "Invalid type in config for key 'badAfter' in 'z', got boolean, wanted object",
411
    );
412
  });
413

414
  it('should read merged objects', () => {
415
    const a = {
416
      merged: {
417
        x: 'x',
418
        z: 'z1',
419
        arr: ['a', 'b'],
420
        config: { d: 'd' },
421
        configs: [{ a: 'a' }],
422
      },
423
    };
424
    const b = {
425
      merged: {
426
        y: 'y',
427
        z: 'z2',
428
        arr: ['c'],
429
        config: { e: 'e' },
430
        configs: [{ b: 'b' }],
431
      },
432
    };
433

434
    const config = new ConfigReader(a, CTX, new ConfigReader(b, CTX));
435

436
    expect(config.keys()).toEqual(['merged']);
437
    expect(config.has('merged.x')).toBe(true);
438
    expect(config.has('merged.y')).toBe(true);
439
    expect(config.has('merged.w')).toBe(false);
440
    expect(config.getConfig('merged').has('x')).toBe(true);
441
    expect(config.getConfig('merged').has('y')).toBe(true);
442
    expect(config.getConfig('merged').has('w')).toBe(false);
443
    expect(config.getConfig('merged').keys()).toEqual([
444
      'x',
445
      'z',
446
      'arr',
447
      'config',
448
      'configs',
449
      'y',
450
    ]);
451
    expect(config.getConfig('merged.config').keys()).toEqual(['d', 'e']);
452

453
    expect(config.getString('merged.x')).toBe('x');
454
    expect(config.getString('merged.y')).toBe('y');
455
    expect(config.getString('merged.z')).toBe('z1');
456
    expect(config.getConfig('merged').getString('x')).toBe('x');
457
    expect(config.getConfig('merged').getString('y')).toBe('y');
458
    expect(config.getConfig('merged').getString('z')).toBe('z1');
459
    expect(config.getString('merged.config.d')).toBe('d');
460
    expect(config.getString('merged.config.e')).toBe('e');
461
    expect(config.getConfig('merged').getString('config.d')).toBe('d');
462
    expect(config.getConfig('merged').getString('config.e')).toBe('e');
463
    expect(config.getConfig('merged').getConfig('config').getString('d')).toBe(
464
      'd',
465
    );
466
    expect(config.getConfig('merged').getConfig('config').getString('e')).toBe(
467
      'e',
468
    );
469

470
    // Arrays are not merged
471
    expect(config.getStringArray('merged.arr')).toEqual(['a', 'b']);
472
    expect(config.getConfig('merged').getStringArray('arr')).toEqual([
473
      'a',
474
      'b',
475
    ]);
476
    expect(() => config.getConfig('merged').getStringArray('x')).toThrow(
477
      "Invalid type in config for key 'merged.x' in 'ctx', got string, wanted string-array",
478
    );
479

480
    // Config arrays aren't merged either
481
    expect(config.getConfigArray('merged.configs').length).toBe(1);
482
    expect(config.getConfigArray('merged.configs')[0].getString('a')).toBe('a');
483
    expect(config.getConfigArray('merged.configs')[0].getString('a')).toBe('a');
484
    expect(() =>
485
      config.getConfigArray('merged.configs')[0].getString('missing'),
486
    ).toThrow("Missing required config value at 'merged.configs[0].missing'");
487
    expect(
488
      config.getConfigArray('merged.configs')[0].getOptionalString('b'),
489
    ).toBeUndefined();
490

491
    // Config arrays aren't merged either
492
    expect(config.getConfig('merged').getConfigArray('configs').length).toBe(1);
493
    expect(
494
      config.getConfig('merged').getConfigArray('configs')[0].getString('a'),
495
    ).toBe('a');
496
    expect(
497
      config
498
        .getConfig('merged')
499
        .getConfigArray('configs')[0]
500
        .getOptionalString('b'),
501
    ).toBeUndefined();
502
  });
503
});
504

505
describe('ConfigReader.get()', () => {
506
  const config1 = {
507
    a: {
508
      x: 'x1',
509
      y: ['y11', 'y12', 'y13'],
510
      z: false,
511
    },
512
    b: {
513
      x: 'x1',
514
      y: ['y11'],
515
    },
516
  };
517
  const config2 = {
518
    b: {
519
      x: 'x2',
520
      y: ['y21', 'y22'],
521
      z: 'z2',
522
    },
523
    c: {
524
      c1: {
525
        c2: 'c2',
526
      },
527
    },
528
  };
529
  const config3 = {
530
    c: {
531
      c1: 'c1',
532
    },
533
  };
534
  const configs = [
535
    {
536
      data: config1,
537
      context: '1',
538
    },
539
    {
540
      data: config2,
541
      context: '2',
542
    },
543
    {
544
      data: config3,
545
      context: '3',
546
    },
547
  ];
548

549
  it('should be able to select sub-configs', () => {
550
    expect(new ConfigReader(config1).get('a')).toEqual(config1.a);
551
    expect(new ConfigReader(config1).get('b')).toEqual(config1.b);
552
    expect(new ConfigReader(config2).get('b')).toEqual(config2.b);
553
    expect(new ConfigReader(config2).get('c')).toEqual(config2.c);
554
    expect(new ConfigReader(config3).get('c')).toEqual(config3.c);
555
    expect(new ConfigReader(config2).get('c.c1')).toEqual(config2.c.c1);
556
    expect(new ConfigReader(config2).getConfig('c').get('c1')).toEqual(
557
      config2.c.c1,
558
    );
559
  });
560

561
  it('should merge in fallback configs', () => {
562
    expect(
563
      ConfigReader.fromConfigs([configs[0], configs[1], configs[2]]).get(),
564
    ).toEqual({
565
      a: {
566
        x: 'x1',
567
        y: ['y11', 'y12', 'y13'],
568
        z: false,
569
      },
570
      b: {
571
        x: 'x2',
572
        y: ['y21', 'y22'],
573
        z: 'z2',
574
      },
575
      c: { c1: 'c1' },
576
    });
577
    expect(ConfigReader.fromConfigs([configs[1], configs[0]]).get('a')).toEqual(
578
      {
579
        x: 'x1',
580
        y: ['y11', 'y12', 'y13'],
581
        z: false,
582
      },
583
    );
584
    expect(ConfigReader.fromConfigs([configs[1], configs[0]]).get('b')).toEqual(
585
      {
586
        x: 'x1',
587
        y: ['y11'],
588
        z: 'z2',
589
      },
590
    );
591
    expect(ConfigReader.fromConfigs([configs[1], configs[0]]).get('c')).toEqual(
592
      {
593
        c1: {
594
          c2: 'c2',
595
        },
596
      },
597
    );
598
    expect(ConfigReader.fromConfigs([configs[1], configs[0]]).get('a')).toEqual(
599
      {
600
        x: 'x1',
601
        y: ['y11', 'y12', 'y13'],
602
        z: false,
603
      },
604
    );
605
    expect(ConfigReader.fromConfigs([configs[1], configs[0]]).get('b')).toEqual(
606
      {
607
        x: 'x1',
608
        y: ['y11'],
609
        z: 'z2',
610
      },
611
    );
612
    expect(ConfigReader.fromConfigs([configs[1], configs[0]]).get('c')).toEqual(
613
      {
614
        c1: {
615
          c2: 'c2',
616
        },
617
      },
618
    );
619

620
    expect(
621
      ConfigReader.fromConfigs([configs[1], configs[2]]).getOptional('b'),
622
    ).toEqual({
623
      x: 'x2',
624
      y: ['y21', 'y22'],
625
      z: 'z2',
626
    });
627
    expect(
628
      ConfigReader.fromConfigs([configs[1], configs[2]]).getOptional('c'),
629
    ).toEqual({
630
      c1: 'c1',
631
    });
632
  });
633

634
  it('should not merge non-objects', () => {
635
    const config = ConfigReader.fromConfigs([
636
      {
637
        data: {
638
          a: ['x', 'y', 'z'],
639
          b: ['1'],
640
          c: ['1'],
641
          d: ['2'],
642
          e: {
643
            y: 'y',
644
          },
645
          f: { x: 'x' },
646
          g: 'bar',
647
          h: {
648
            a: 'a2',
649
            b: 'b2',
650
          },
651
        },
652
        context: '2',
653
      },
654
      {
655
        data: {
656
          a: ['1', '2'],
657
          c: [],
658
          d: {
659
            x: 'x',
660
          },
661
          e: ['3'],
662
          f: 'foo',
663
          g: { z: 'z' },
664
          h: {
665
            a: 'a1',
666
            c: 'c1',
667
          },
668
        },
669
        context: '1',
670
      },
671
    ]);
672
    expect(config.get('a')).toEqual(['1', '2']);
673
    expect(config.get('b')).toEqual(['1']);
674
    expect(config.get('c')).toEqual([]);
675
    expect(config.get('d')).toEqual({ x: 'x' });
676
    expect(config.get('e')).toEqual(['3']);
677
    expect(config.get('f')).toEqual('foo');
678
    expect(config.get('g')).toEqual({ z: 'z' });
679
    expect(config.get('h')).toEqual({ a: 'a1', b: 'b2', c: 'c1' });
680
    expect(config.getConfig('h').get()).toEqual({ a: 'a1', b: 'b2', c: 'c1' });
681
    expect(config.getOptional()).toEqual({
682
      a: ['1', '2'],
683
      b: ['1'],
684
      c: [],
685
      d: {
686
        x: 'x',
687
      },
688
      e: ['3'],
689
      f: 'foo',
690
      g: { z: 'z' },
691
      h: {
692
        a: 'a1',
693
        b: 'b2',
694
        c: 'c1',
695
      },
696
    });
697
  });
698

699
  it('should return deep clones of the backing data', () => {
700
    const data1 = {
701
      foo: {
702
        bar: [],
703
        baz: {},
704
      },
705
    };
706
    const data2 = {
707
      x: {
708
        y: {
709
          z: {},
710
        },
711
      },
712
    };
713

714
    const reader = ConfigReader.fromConfigs([
715
      { data: data1, context: '1' },
716
      { data: data2, context: '2' },
717
    ]);
718

719
    reader.get<any>().foo.bar.push(1);
720
    reader.get<any>('foo').bar.push(1);
721
    reader.get<any>('foo.bar').push(1);
722
    reader.get<any>().foo.baz.x = 1;
723
    reader.get<any>('foo').baz.x = 1;
724
    reader.get<any>('foo.baz').x = 1;
725
    reader.get<any>().x.y.z.w = 1;
726
    reader.get<any>('x').y.z.w = 1;
727
    reader.get<any>('x.y').z.w = 1;
728
    reader.get<any>('x.y.z').w = 1;
729

730
    const readerSingle = ConfigReader.fromConfigs([
731
      { data: data1, context: '1' },
732
    ]);
733

734
    readerSingle.get<any>().foo.bar.push(1);
735
    readerSingle.get<any>('foo').bar.push(1);
736
    readerSingle.get<any>('foo.bar').push(1);
737
    readerSingle.get<any>().foo.baz.x = 1;
738
    readerSingle.get<any>('foo').baz.x = 1;
739
    readerSingle.get<any>('foo.baz').x = 1;
740

741
    expect(data1.foo.bar).toEqual([]);
742
    expect(data1.foo.baz).toEqual({});
743
    expect(data2.x.y.z).toEqual({});
744
  });
745
});
746

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.