@adobe/spacecat-shared-tokowaka-client 1.5.8 → 1.6.1
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/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/index.js +20 -27
- package/src/utils/custom-html-utils.js +2 -6
- package/test/index.test.js +170 -39
- package/test/utils/html-utils.test.js +27 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-tokowaka-client-v1.6.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.6.0...@adobe/spacecat-shared-tokowaka-client-v1.6.1) (2026-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* api key now optional for edge-preview ([#1299](https://github.com/adobe/spacecat-shared/issues/1299)) ([76eb046](https://github.com/adobe/spacecat-shared/commit/76eb04640dab752a83909a51827abde1e41fc57e))
|
|
7
|
+
|
|
8
|
+
# [@adobe/spacecat-shared-tokowaka-client-v1.6.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.5.8...@adobe/spacecat-shared-tokowaka-client-v1.6.0) (2026-01-29)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* new flag opted added in edgeoptimizeconfig ([#1294](https://github.com/adobe/spacecat-shared/issues/1294)) ([8386e38](https://github.com/adobe/spacecat-shared/commit/8386e3805e9e67c18e4569428bef7ac5723eb991))
|
|
14
|
+
|
|
1
15
|
# [@adobe/spacecat-shared-tokowaka-client-v1.5.8](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.5.7...@adobe/spacecat-shared-tokowaka-client-v1.5.8) (2026-01-27)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -290,7 +290,7 @@ class TokowakaClient {
|
|
|
290
290
|
* @param {boolean} options.enhancements - Whether to enable enhancements (default: true)
|
|
291
291
|
* @returns {Promise<Object>} - Object with s3Path and metaconfig
|
|
292
292
|
*/
|
|
293
|
-
async createMetaconfig(url, siteId, options = {}) {
|
|
293
|
+
async createMetaconfig(url, siteId, options = {}, metadata = {}) {
|
|
294
294
|
if (!hasText(url)) {
|
|
295
295
|
throw this.#createError('URL is required', HTTP_BAD_REQUEST);
|
|
296
296
|
}
|
|
@@ -316,8 +316,7 @@ class TokowakaClient {
|
|
|
316
316
|
patches: {},
|
|
317
317
|
};
|
|
318
318
|
|
|
319
|
-
const s3Path = await this.uploadMetaconfig(url, metaconfig);
|
|
320
|
-
|
|
319
|
+
const s3Path = await this.uploadMetaconfig(url, metaconfig, metadata);
|
|
321
320
|
this.log.info(`Created new Tokowaka metaconfig for ${normalizedHostName} at ${s3Path}`);
|
|
322
321
|
|
|
323
322
|
return metaconfig;
|
|
@@ -331,7 +330,7 @@ class TokowakaClient {
|
|
|
331
330
|
* @param {Object} options - Optional configuration
|
|
332
331
|
* @returns {Promise<Object>} - Object with s3Path and metaconfig
|
|
333
332
|
*/
|
|
334
|
-
async updateMetaconfig(url, siteId, options = {}) {
|
|
333
|
+
async updateMetaconfig(url, siteId, options = {}, metadata = {}) {
|
|
335
334
|
if (!hasText(url)) {
|
|
336
335
|
throw this.#createError('URL is required', HTTP_BAD_REQUEST);
|
|
337
336
|
}
|
|
@@ -371,8 +370,7 @@ class TokowakaClient {
|
|
|
371
370
|
...(hasPrerender && { prerender }),
|
|
372
371
|
};
|
|
373
372
|
|
|
374
|
-
const s3Path = await this.uploadMetaconfig(url, metaconfig);
|
|
375
|
-
|
|
373
|
+
const s3Path = await this.uploadMetaconfig(url, metaconfig, metadata);
|
|
376
374
|
this.log.info(`Updated Tokowaka metaconfig for ${normalizedHostName} at ${s3Path}`);
|
|
377
375
|
|
|
378
376
|
return metaconfig;
|
|
@@ -382,9 +380,10 @@ class TokowakaClient {
|
|
|
382
380
|
* Uploads domain-level metaconfig to S3
|
|
383
381
|
* @param {string} url - Full URL (used to extract domain)
|
|
384
382
|
* @param {Object} metaconfig - Metaconfig object (siteId, apiKeys, prerender)
|
|
383
|
+
* @param {Object} metadata - Optional S3 user-defined metadata (key-value pairs)
|
|
385
384
|
* @returns {Promise<string>} - S3 key of uploaded metaconfig
|
|
386
|
-
|
|
387
|
-
async uploadMetaconfig(url, metaconfig) {
|
|
385
|
+
*/
|
|
386
|
+
async uploadMetaconfig(url, metaconfig, metadata = {}) {
|
|
388
387
|
if (!hasText(url)) {
|
|
389
388
|
throw this.#createError('URL is required', HTTP_BAD_REQUEST);
|
|
390
389
|
}
|
|
@@ -397,12 +396,19 @@ class TokowakaClient {
|
|
|
397
396
|
const bucketName = this.deployBucketName;
|
|
398
397
|
|
|
399
398
|
try {
|
|
400
|
-
const
|
|
399
|
+
const putObjectParams = {
|
|
401
400
|
Bucket: bucketName,
|
|
402
401
|
Key: s3Path,
|
|
403
402
|
Body: JSON.stringify(metaconfig, null, 2),
|
|
404
403
|
ContentType: 'application/json',
|
|
405
|
-
}
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// Add user-defined metadata if provided
|
|
407
|
+
if (isNonEmptyObject(metadata)) {
|
|
408
|
+
putObjectParams.Metadata = metadata;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const command = new PutObjectCommand(putObjectParams);
|
|
406
412
|
|
|
407
413
|
await this.s3Client.send(command);
|
|
408
414
|
this.log.info(`Successfully uploaded metaconfig to s3://${bucketName}/${s3Path}`);
|
|
@@ -907,26 +913,13 @@ class TokowakaClient {
|
|
|
907
913
|
}
|
|
908
914
|
|
|
909
915
|
// Fetch metaconfig to get API key
|
|
910
|
-
const metaconfig = await this.fetchMetaconfig(previewUrl);
|
|
916
|
+
const metaconfig = await this.fetchMetaconfig(previewUrl) || {};
|
|
911
917
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
+ 'A domain-level metaconfig needs to be created first before previewing suggestions.',
|
|
916
|
-
HTTP_INTERNAL_SERVER_ERROR,
|
|
917
|
-
);
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
const { apiKeys } = metaconfig;
|
|
921
|
-
if (!Array.isArray(apiKeys) || apiKeys.length === 0 || !hasText(apiKeys[0])) {
|
|
922
|
-
throw this.#createError(
|
|
923
|
-
'Metaconfig does not have valid API keys configured. '
|
|
924
|
-
+ 'Please ensure the metaconfig has at least one API key.',
|
|
925
|
-
HTTP_INTERNAL_SERVER_ERROR,
|
|
926
|
-
);
|
|
918
|
+
let apiKey;
|
|
919
|
+
if (Array.isArray(metaconfig.apiKeys) && metaconfig.apiKeys.length > 0) {
|
|
920
|
+
[apiKey] = metaconfig.apiKeys;
|
|
927
921
|
}
|
|
928
922
|
|
|
929
|
-
const apiKey = apiKeys[0];
|
|
930
923
|
const forwardedHost = calculateForwardedHost(previewUrl, this.log);
|
|
931
924
|
|
|
932
925
|
// Fetch existing deployed configuration for this URL from production S3
|
|
@@ -104,7 +104,7 @@ async function fetchWithRetry(url, options, maxRetries, retryDelayMs, log, fetch
|
|
|
104
104
|
* Fetches HTML content from edge with warmup call and retry logic
|
|
105
105
|
* Makes an initial warmup call, waits, then makes the actual call with retries
|
|
106
106
|
* @param {string} url - Full URL to fetch
|
|
107
|
-
* @param {string} apiKey - Edge Optimize API key
|
|
107
|
+
* @param {string} apiKey - Edge Optimize API key (optional)
|
|
108
108
|
* @param {string} forwardedHost - Host to forward in x-forwarded-host header
|
|
109
109
|
* @param {string} edgeUrl - Edge URL
|
|
110
110
|
* @param {boolean} isOptimized - Whether to fetch optimized HTML (with preview param)
|
|
@@ -130,10 +130,6 @@ export async function fetchHtmlWithWarmup(
|
|
|
130
130
|
throw new Error('URL is required for fetching HTML');
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
if (!hasText(apiKey)) {
|
|
134
|
-
throw new Error('Edge Optimize API key is required for fetching HTML');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
133
|
if (!hasText(forwardedHost)) {
|
|
138
134
|
throw new Error('Forwarded host is required for fetching HTML');
|
|
139
135
|
}
|
|
@@ -158,7 +154,7 @@ export async function fetchHtmlWithWarmup(
|
|
|
158
154
|
|
|
159
155
|
const headers = {
|
|
160
156
|
'x-forwarded-host': forwardedHost,
|
|
161
|
-
'x-edgeoptimize-api-key': apiKey,
|
|
157
|
+
...(apiKey && { 'x-edgeoptimize-api-key': apiKey }),
|
|
162
158
|
'x-edgeoptimize-url': urlPath,
|
|
163
159
|
'Accept-Encoding': 'identity', // Disable compression to avoid content-length: 0 issue
|
|
164
160
|
};
|
package/test/index.test.js
CHANGED
|
@@ -454,6 +454,43 @@ describe('TokowakaClient', () => {
|
|
|
454
454
|
expect(error.status).to.equal(500);
|
|
455
455
|
}
|
|
456
456
|
});
|
|
457
|
+
|
|
458
|
+
it('should upload metaconfig with user-defined metadata when provided', async () => {
|
|
459
|
+
const metaconfig = {
|
|
460
|
+
siteId: 'site-123',
|
|
461
|
+
prerender: true,
|
|
462
|
+
};
|
|
463
|
+
const metadata = {
|
|
464
|
+
'last-modified-by': 'john@example.com',
|
|
465
|
+
'created-by': 'admin',
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
const s3Path = await client.uploadMetaconfig('https://example.com/page1', metaconfig, metadata);
|
|
469
|
+
|
|
470
|
+
expect(s3Path).to.equal('opportunities/example.com/config');
|
|
471
|
+
|
|
472
|
+
const command = s3Client.send.firstCall.args[0];
|
|
473
|
+
expect(command.input.Bucket).to.equal('test-bucket');
|
|
474
|
+
expect(command.input.Key).to.equal('opportunities/example.com/config');
|
|
475
|
+
expect(command.input.ContentType).to.equal('application/json');
|
|
476
|
+
expect(JSON.parse(command.input.Body)).to.deep.equal(metaconfig);
|
|
477
|
+
expect(command.input.Metadata).to.deep.equal(metadata);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it('should upload metaconfig without Metadata field when metadata is empty object', async () => {
|
|
481
|
+
const metaconfig = {
|
|
482
|
+
siteId: 'site-123',
|
|
483
|
+
prerender: true,
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
const s3Path = await client.uploadMetaconfig('https://example.com/page1', metaconfig, {});
|
|
487
|
+
|
|
488
|
+
expect(s3Path).to.equal('opportunities/example.com/config');
|
|
489
|
+
|
|
490
|
+
const command = s3Client.send.firstCall.args[0];
|
|
491
|
+
expect(command.input.Bucket).to.equal('test-bucket');
|
|
492
|
+
expect(command.input.Metadata).to.be.undefined;
|
|
493
|
+
});
|
|
457
494
|
});
|
|
458
495
|
|
|
459
496
|
describe('createMetaconfig', () => {
|
|
@@ -567,6 +604,50 @@ describe('TokowakaClient', () => {
|
|
|
567
604
|
const command = s3Client.send.firstCall.args[0];
|
|
568
605
|
expect(command.input.Key).to.equal('opportunities/example.com/config');
|
|
569
606
|
});
|
|
607
|
+
|
|
608
|
+
it('should include user-defined metadata when metadata is provided', async () => {
|
|
609
|
+
const siteId = 'site-123';
|
|
610
|
+
const url = 'https://www.example.com/page1';
|
|
611
|
+
const noSuchKeyError = new Error('NoSuchKey');
|
|
612
|
+
noSuchKeyError.name = 'NoSuchKey';
|
|
613
|
+
s3Client.send.onFirstCall().rejects(noSuchKeyError);
|
|
614
|
+
|
|
615
|
+
await client.createMetaconfig(url, siteId, {}, { 'last-modified-by': 'john@example.com' });
|
|
616
|
+
|
|
617
|
+
// Second call is the uploadMetaconfig
|
|
618
|
+
const uploadCommand = s3Client.send.secondCall.args[0];
|
|
619
|
+
expect(uploadCommand.input.Metadata).to.deep.equal({
|
|
620
|
+
'last-modified-by': 'john@example.com',
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
it('should not include metadata when metadata is empty object', async () => {
|
|
625
|
+
const siteId = 'site-123';
|
|
626
|
+
const url = 'https://www.example.com/page1';
|
|
627
|
+
const noSuchKeyError = new Error('NoSuchKey');
|
|
628
|
+
noSuchKeyError.name = 'NoSuchKey';
|
|
629
|
+
s3Client.send.onFirstCall().rejects(noSuchKeyError);
|
|
630
|
+
|
|
631
|
+
await client.createMetaconfig(url, siteId, {}, {});
|
|
632
|
+
|
|
633
|
+
// Second call is the uploadMetaconfig
|
|
634
|
+
const uploadCommand = s3Client.send.secondCall.args[0];
|
|
635
|
+
expect(uploadCommand.input.Metadata).to.be.undefined;
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it('should not include metadata when metadata is not provided', async () => {
|
|
639
|
+
const siteId = 'site-123';
|
|
640
|
+
const url = 'https://www.example.com/page1';
|
|
641
|
+
const noSuchKeyError = new Error('NoSuchKey');
|
|
642
|
+
noSuchKeyError.name = 'NoSuchKey';
|
|
643
|
+
s3Client.send.onFirstCall().rejects(noSuchKeyError);
|
|
644
|
+
|
|
645
|
+
await client.createMetaconfig(url, siteId);
|
|
646
|
+
|
|
647
|
+
// Second call is the uploadMetaconfig
|
|
648
|
+
const uploadCommand = s3Client.send.secondCall.args[0];
|
|
649
|
+
expect(uploadCommand.input.Metadata).to.be.undefined;
|
|
650
|
+
});
|
|
570
651
|
});
|
|
571
652
|
|
|
572
653
|
describe('updateMetaconfig', () => {
|
|
@@ -1308,6 +1389,47 @@ describe('TokowakaClient', () => {
|
|
|
1308
1389
|
expect(result).to.have.property('prerender');
|
|
1309
1390
|
expect(result.prerender).to.deep.equal(prerenderConfig);
|
|
1310
1391
|
});
|
|
1392
|
+
|
|
1393
|
+
it('should include user-defined metadata when metadata is provided', async () => {
|
|
1394
|
+
const siteId = 'site-456';
|
|
1395
|
+
const url = 'https://www.example.com';
|
|
1396
|
+
|
|
1397
|
+
await client.updateMetaconfig(url, siteId, {
|
|
1398
|
+
tokowakaEnabled: true,
|
|
1399
|
+
}, { 'last-modified-by': 'jane@example.com' });
|
|
1400
|
+
|
|
1401
|
+
// Second call is the uploadMetaconfig
|
|
1402
|
+
const uploadCommand = s3Client.send.secondCall.args[0];
|
|
1403
|
+
expect(uploadCommand.input.Metadata).to.deep.equal({
|
|
1404
|
+
'last-modified-by': 'jane@example.com',
|
|
1405
|
+
});
|
|
1406
|
+
});
|
|
1407
|
+
|
|
1408
|
+
it('should not include metadata when metadata is empty object', async () => {
|
|
1409
|
+
const siteId = 'site-456';
|
|
1410
|
+
const url = 'https://www.example.com';
|
|
1411
|
+
|
|
1412
|
+
await client.updateMetaconfig(url, siteId, {
|
|
1413
|
+
tokowakaEnabled: true,
|
|
1414
|
+
}, {});
|
|
1415
|
+
|
|
1416
|
+
// Second call is the uploadMetaconfig
|
|
1417
|
+
const uploadCommand = s3Client.send.secondCall.args[0];
|
|
1418
|
+
expect(uploadCommand.input.Metadata).to.be.undefined;
|
|
1419
|
+
});
|
|
1420
|
+
|
|
1421
|
+
it('should not include metadata when metadata is not provided', async () => {
|
|
1422
|
+
const siteId = 'site-456';
|
|
1423
|
+
const url = 'https://www.example.com';
|
|
1424
|
+
|
|
1425
|
+
await client.updateMetaconfig(url, siteId, {
|
|
1426
|
+
tokowakaEnabled: true,
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1429
|
+
// Second call is the uploadMetaconfig
|
|
1430
|
+
const uploadCommand = s3Client.send.secondCall.args[0];
|
|
1431
|
+
expect(uploadCommand.input.Metadata).to.be.undefined;
|
|
1432
|
+
});
|
|
1311
1433
|
});
|
|
1312
1434
|
|
|
1313
1435
|
describe('uploadConfig', () => {
|
|
@@ -2819,61 +2941,70 @@ describe('TokowakaClient', () => {
|
|
|
2819
2941
|
}
|
|
2820
2942
|
});
|
|
2821
2943
|
|
|
2822
|
-
it('should
|
|
2944
|
+
it('should preview suggestions successfully without metaconfig (optional)', async () => {
|
|
2945
|
+
// Override the stub from beforeEach to return null
|
|
2823
2946
|
client.fetchMetaconfig.resolves(null);
|
|
2824
2947
|
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
}
|
|
2832
|
-
});
|
|
2948
|
+
const result = await client.previewSuggestions(
|
|
2949
|
+
mockSite,
|
|
2950
|
+
mockOpportunity,
|
|
2951
|
+
mockSuggestions,
|
|
2952
|
+
{ warmupDelayMs: 0 },
|
|
2953
|
+
);
|
|
2833
2954
|
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2955
|
+
expect(result.succeededSuggestions).to.have.length(2);
|
|
2956
|
+
expect(result.failedSuggestions).to.have.length(0);
|
|
2957
|
+
expect(result.config).to.exist;
|
|
2958
|
+
expect(result.html).to.exist;
|
|
2959
|
+
expect(result.html.originalHtml).to.equal('<html><body>Test HTML</body></html>');
|
|
2960
|
+
expect(result.html.optimizedHtml).to.equal('<html><body>Test HTML</body></html>');
|
|
2839
2961
|
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
expect.fail('Should have thrown error');
|
|
2843
|
-
} catch (error) {
|
|
2844
|
-
expect(error.message).to.include('Metaconfig does not have valid API keys configured');
|
|
2845
|
-
expect(error.status).to.equal(500);
|
|
2846
|
-
}
|
|
2962
|
+
// Verify fetch was called without API key (undefined)
|
|
2963
|
+
expect(fetchStub.callCount).to.equal(4); // 2 warmup + 2 actual (original + optimized)
|
|
2847
2964
|
});
|
|
2848
2965
|
|
|
2849
|
-
it('should
|
|
2966
|
+
it('should preview suggestions successfully without apiKeys in metaconfig (optional)', async () => {
|
|
2967
|
+
// Override the stub from beforeEach
|
|
2850
2968
|
client.fetchMetaconfig.resolves({
|
|
2851
2969
|
siteId: 'site-123',
|
|
2852
|
-
apiKeys
|
|
2970
|
+
// apiKeys missing - should work without it
|
|
2853
2971
|
});
|
|
2854
2972
|
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2973
|
+
const result = await client.previewSuggestions(
|
|
2974
|
+
mockSite,
|
|
2975
|
+
mockOpportunity,
|
|
2976
|
+
mockSuggestions,
|
|
2977
|
+
{ warmupDelayMs: 0 },
|
|
2978
|
+
);
|
|
2979
|
+
|
|
2980
|
+
expect(result.succeededSuggestions).to.have.length(2);
|
|
2981
|
+
expect(result.failedSuggestions).to.have.length(0);
|
|
2982
|
+
expect(result.config).to.exist;
|
|
2983
|
+
expect(result.html).to.exist;
|
|
2984
|
+
expect(result.html.originalHtml).to.equal('<html><body>Test HTML</body></html>');
|
|
2985
|
+
expect(result.html.optimizedHtml).to.equal('<html><body>Test HTML</body></html>');
|
|
2986
|
+
expect(fetchStub.callCount).to.equal(4);
|
|
2862
2987
|
});
|
|
2863
2988
|
|
|
2864
|
-
it('should
|
|
2989
|
+
it('should preview suggestions successfully with empty apiKeys array (optional)', async () => {
|
|
2990
|
+
// Override the stub from beforeEach
|
|
2865
2991
|
client.fetchMetaconfig.resolves({
|
|
2866
2992
|
siteId: 'site-123',
|
|
2867
|
-
apiKeys: [
|
|
2993
|
+
apiKeys: [],
|
|
2868
2994
|
});
|
|
2869
2995
|
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2996
|
+
const result = await client.previewSuggestions(
|
|
2997
|
+
mockSite,
|
|
2998
|
+
mockOpportunity,
|
|
2999
|
+
mockSuggestions,
|
|
3000
|
+
{ warmupDelayMs: 0 },
|
|
3001
|
+
);
|
|
3002
|
+
|
|
3003
|
+
expect(result.succeededSuggestions).to.have.length(2);
|
|
3004
|
+
expect(result.failedSuggestions).to.have.length(0);
|
|
3005
|
+
expect(result.config).to.exist;
|
|
3006
|
+
expect(result.html).to.exist;
|
|
3007
|
+
expect(fetchStub.callCount).to.equal(4);
|
|
2877
3008
|
});
|
|
2878
3009
|
|
|
2879
3010
|
it('should throw error for unsupported opportunity type', async () => {
|
|
@@ -82,20 +82,33 @@ describe('HTML Utils', () => {
|
|
|
82
82
|
}
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
it('should
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
'
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
85
|
+
it('should successfully fetch HTML without apiKey (optional parameter)', async () => {
|
|
86
|
+
fetchStub.resolves({
|
|
87
|
+
ok: true,
|
|
88
|
+
status: 200,
|
|
89
|
+
statusText: 'OK',
|
|
90
|
+
headers: {
|
|
91
|
+
get: (name) => (name === 'x-edgeoptimize-cache' ? 'HIT' : null),
|
|
92
|
+
},
|
|
93
|
+
text: async () => '<html>Test HTML without API key</html>',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const html = await fetchHtmlWithWarmup(
|
|
97
|
+
'https://example.com/page',
|
|
98
|
+
null, // apiKey is optional
|
|
99
|
+
'host',
|
|
100
|
+
'https://edge.example.com',
|
|
101
|
+
log,
|
|
102
|
+
false,
|
|
103
|
+
{ warmupDelayMs: 0 },
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(html).to.equal('<html>Test HTML without API key</html>');
|
|
107
|
+
expect(fetchStub.callCount).to.equal(2); // warmup + actual
|
|
108
|
+
|
|
109
|
+
// Verify that x-edgeoptimize-api-key header is not present
|
|
110
|
+
const fetchOptions = fetchStub.firstCall.args[1];
|
|
111
|
+
expect(fetchOptions.headers).to.not.have.property('x-edgeoptimize-api-key');
|
|
99
112
|
});
|
|
100
113
|
|
|
101
114
|
it('should successfully fetch HTML with all required parameters', async () => {
|