-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathjson.test.ts
More file actions
175 lines (154 loc) · 8.38 KB
/
json.test.ts
File metadata and controls
175 lines (154 loc) · 8.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
/* eslint-disable @typescript-eslint/no-unused-expressions */
import * as chai from "chai";
import chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
const expect = chai.expect;
import { load } from "../src/index.js";
import { mockAppConfigurationClientListConfigurationSettings, restoreMocks, createMockedConnectionString, createMockedKeyVaultReference, createMockedJsonKeyValue } from "./utils/testHelper.js";
const jsonKeyValue = createMockedJsonKeyValue("json.settings.logging", '{"Test":{"Level":"Debug"},"Prod":{"Level":"Warning"}}');
const keyVaultKeyValue = createMockedKeyVaultReference("TestKey", "https://fake-vault-name.vault.azure.net/secrets/fakeSecretName");
describe("json", function () {
beforeEach(() => {
});
afterEach(() => {
restoreMocks();
});
it("should load and parse if content type is application/json", async () => {
mockAppConfigurationClientListConfigurationSettings([[jsonKeyValue]]);
const connectionString = createMockedConnectionString();
const settings = await load(connectionString);
expect(settings).not.undefined;
const logging = settings.get<any>("json.settings.logging");
expect(logging).not.undefined;
expect(logging.Test).not.undefined;
expect(logging.Test.Level).eq("Debug");
expect(logging.Prod).not.undefined;
expect(logging.Prod.Level).eq("Warning");
});
it("should not parse key-vault reference", async () => {
mockAppConfigurationClientListConfigurationSettings([[jsonKeyValue, keyVaultKeyValue]]);
const connectionString = createMockedConnectionString();
const settings = await load(connectionString, {
keyVaultOptions: {
secretResolver: (url) => `Resolved: ${url.toString()}`
}
});
expect(settings).not.undefined;
const resolvedSecret = settings.get<any>("TestKey");
expect(resolvedSecret).not.undefined;
expect(resolvedSecret.uri).undefined;
expect(typeof resolvedSecret).eq("string");
});
it("should parse different kinds of legal values", async () => {
mockAppConfigurationClientListConfigurationSettings([[
/**
* A JSON value MUST be an object, array, number, or string, false, null, true
* See https://www.ietf.org/rfc/rfc4627.txt
*/
createMockedJsonKeyValue("json.settings.object", "{}"),
createMockedJsonKeyValue("json.settings.array", "[]"),
createMockedJsonKeyValue("json.settings.number", "8"),
createMockedJsonKeyValue("json.settings.string", "\"string\""),
createMockedJsonKeyValue("json.settings.false", "false"),
createMockedJsonKeyValue("json.settings.true", "true"),
createMockedJsonKeyValue("json.settings.null", "null"),
createMockedJsonKeyValue("json.settings.literalNull", null), // possible value via Portal's advanced edit.
// Special tricky values related to JavaScript
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean#boolean_coercion
createMockedJsonKeyValue("json.settings.zero", 0),
createMockedJsonKeyValue("json.settings.emptyString", ""), // should fail JSON.parse and use string value as fallback
createMockedJsonKeyValue("json.settings.illegalString", "[unclosed"), // should fail JSON.parse
]]);
const connectionString = createMockedConnectionString();
const settings = await load(connectionString);
expect(settings).not.undefined;
expect(typeof settings.get("json.settings.object")).eq("object", "is object");
expect(Object.keys(settings.get<any>("json.settings.object")).length).eq(0, "is empty object");
expect(Array.isArray(settings.get("json.settings.array"))).eq(true, "is array");
expect(settings.get("json.settings.number")).eq(8, "is number");
expect(settings.get("json.settings.string")).eq("string", "is string");
expect(settings.get("json.settings.false")).eq(false, "is false");
expect(settings.get("json.settings.true")).eq(true, "is true");
expect(settings.get("json.settings.null")).eq(null, "is null");
expect(settings.get("json.settings.literalNull")).eq(null, "is literal null");
expect(settings.get("json.settings.zero")).eq(0, "is zero");
expect(settings.get("json.settings.emptyString")).eq("", "is empty string");
expect(settings.get("json.settings.illegalString")).eq("[unclosed", "is illegal string");
});
it("should load json values with comments", async () => {
// Test various comment styles and positions
const mixedCommentStylesValue = `{
// Single line comment at start
"ApiSettings": {
"BaseUrl": "https://api.example.com", // Inline single line
/* Multi-line comment
spanning multiple lines */
"ApiKey": "secret-key",
"Endpoints": [
// Comment before array element
"/users",
/* Comment between elements */
"/orders",
"/products" // Comment after element
]
},
// Test edge cases
"StringWithSlashes": "This is not a // comment",
"StringWithStars": "This is not a /* comment */",
"UrlValue": "https://example.com/path", // This is a real comment
"EmptyComment": "value", //
/**/
"AfterEmptyComment": "value2"
/* Final multi-line comment */
}`;
// Test invalid JSON with comments
const invalidJsonWithCommentsValue = `// This is a comment
{ invalid json structure
// Another comment
missing quotes and braces`;
// Test only comments (should be invalid JSON)
const onlyCommentsValue = `
// Just comments
/* No actual content */
`;
const keyValues = [
createMockedJsonKeyValue("MixedCommentStyles", mixedCommentStylesValue),
createMockedJsonKeyValue("InvalidJsonWithComments", invalidJsonWithCommentsValue),
createMockedJsonKeyValue("OnlyComments", onlyCommentsValue)
];
mockAppConfigurationClientListConfigurationSettings([keyValues]);
const connectionString = createMockedConnectionString();
const settings = await load(connectionString);
expect(settings).not.undefined;
// Verify mixed comment styles are properly parsed
const mixedConfig = settings.get<any>("MixedCommentStyles");
expect(mixedConfig).not.undefined;
expect(mixedConfig.ApiSettings).not.undefined;
expect(mixedConfig.ApiSettings.BaseUrl).eq("https://api.example.com");
expect(mixedConfig.ApiSettings.ApiKey).eq("secret-key");
expect(mixedConfig.ApiSettings.Endpoints).not.undefined;
expect(Array.isArray(mixedConfig.ApiSettings.Endpoints)).eq(true);
expect(mixedConfig.ApiSettings.Endpoints[0]).eq("/users");
expect(mixedConfig.ApiSettings.Endpoints[1]).eq("/orders");
expect(mixedConfig.ApiSettings.Endpoints[2]).eq("/products");
// Verify edge cases where comment-like text appears in strings
expect(mixedConfig.StringWithSlashes).eq("This is not a // comment");
expect(mixedConfig.StringWithStars).eq("This is not a /* comment */");
expect(mixedConfig.UrlValue).eq("https://example.com/path");
expect(mixedConfig.EmptyComment).eq("value");
expect(mixedConfig.AfterEmptyComment).eq("value2");
// Invalid JSON should fall back to string value
const invalidConfig = settings.get("InvalidJsonWithComments");
expect(invalidConfig).not.undefined;
expect(typeof invalidConfig).eq("string");
expect(invalidConfig).eq(invalidJsonWithCommentsValue);
// Only comments should be treated as string value (invalid JSON)
const onlyCommentsConfig = settings.get("OnlyComments");
expect(onlyCommentsConfig).not.undefined;
expect(typeof onlyCommentsConfig).eq("string");
expect(onlyCommentsConfig).eq(onlyCommentsValue);
});
});
/* eslint-enable @typescript-eslint/no-unused-expressions */