Skip to content

Commit 3ff7841

Browse files
cursoragentAaronDDM
andcommitted
Test URL construction and query parameter encoding
Co-authored-by: aaron.d <[email protected]>
1 parent 64101a7 commit 3ff7841

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

tests/resources/events.spec.ts

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,4 +588,150 @@ describe('Events', () => {
588588
});
589589
});
590590
});
591+
592+
describe('URL construction and encoding (direct API client tests)', () => {
593+
it('should construct URLs with properly encoded query parameters', async () => {
594+
// Test the URL construction by creating a URL and manually calling setQueryStrings
595+
const baseUrl = new URL('https://api.nylas.com/v3/grants/grant-id/events');
596+
const queryParams = {
597+
calendarId: '[email protected]',
598+
start: '1640995200',
599+
end: '1641081600',
600+
limit: 50,
601+
metadataPair: { 'custom-key': 'custom-value' },
602+
};
603+
604+
// Create a real API client to test actual URL construction
605+
const realApiClient = new APIClient({
606+
apiKey: 'test-api-key',
607+
apiUri: 'https://api.nylas.com',
608+
timeout: 30,
609+
headers: {},
610+
});
611+
612+
// Access the private method through bracket notation for testing
613+
const setQueryStrings = (realApiClient as any).setQueryStrings.bind(realApiClient);
614+
const finalUrl = setQueryStrings(baseUrl, queryParams);
615+
616+
// Verify the actual URL that was constructed
617+
const requestUrl = finalUrl.toString();
618+
expect(requestUrl).toContain('?'); // Should have proper query separator
619+
expect(requestUrl).not.toContain('%3F'); // Should not have encoded question mark
620+
expect(requestUrl).toContain('calendar%40example.com'); // Email should be properly encoded
621+
expect(requestUrl).toContain('start=1640995200');
622+
expect(requestUrl).toContain('end=1641081600');
623+
expect(requestUrl).toContain('limit=50');
624+
expect(requestUrl).toContain('metadata_pair=custom-key%3Acustom-value'); // metadataPair should be properly formatted
625+
});
626+
627+
it('should handle special characters in query parameters without double encoding', async () => {
628+
const baseUrl = new URL('https://api.nylas.com/v3/grants/grant-id/events');
629+
const queryParams = {
630+
calendarId: '[email protected]',
631+
title: 'meeting with ? special chars',
632+
metadataPair: { 'key with spaces': 'value with & symbols' },
633+
};
634+
635+
const realApiClient = new APIClient({
636+
apiKey: 'test-api-key',
637+
apiUri: 'https://api.nylas.com',
638+
timeout: 30,
639+
headers: {},
640+
});
641+
642+
const setQueryStrings = (realApiClient as any).setQueryStrings.bind(realApiClient);
643+
const finalUrl = setQueryStrings(baseUrl, queryParams);
644+
const requestUrl = finalUrl.toString();
645+
646+
// Verify proper encoding
647+
expect(requestUrl).toContain('?'); // Should have proper query separator
648+
expect(requestUrl).not.toContain('%3F'); // Should not have encoded question mark
649+
expect(requestUrl).toContain('calendar%2Btest%40example.com'); // + and @ should be properly encoded
650+
expect(requestUrl).toContain('title=meeting%20with%20%3F%20special%20chars'); // Space and ? should be encoded
651+
expect(requestUrl).toContain('metadata_pair=key%20with%20spaces%3Avalue%20with%20%26%20symbols'); // Complex metadata
652+
});
653+
654+
it('should not double-encode already encoded parameters', async () => {
655+
const baseUrl = new URL('https://api.nylas.com/v3/grants/grant-id/events');
656+
const queryParams = {
657+
calendarId: 'calendar%40example.com', // Already URL encoded
658+
title: 'meeting%20with%20special%20chars', // Already URL encoded
659+
};
660+
661+
const realApiClient = new APIClient({
662+
apiKey: 'test-api-key',
663+
apiUri: 'https://api.nylas.com',
664+
timeout: 30,
665+
headers: {},
666+
});
667+
668+
const setQueryStrings = (realApiClient as any).setQueryStrings.bind(realApiClient);
669+
const finalUrl = setQueryStrings(baseUrl, queryParams);
670+
const requestUrl = finalUrl.toString();
671+
672+
// Verify no double encoding occurred
673+
expect(requestUrl).toContain('?'); // Should have proper query separator
674+
expect(requestUrl).not.toContain('%3F'); // Should not have encoded question mark
675+
expect(requestUrl).toContain('calendar%40example.com'); // Should remain as provided (no double encoding)
676+
expect(requestUrl).toContain('title=meeting%20with%20special%20chars'); // Should remain as provided
677+
});
678+
679+
it('should handle array parameters correctly', async () => {
680+
const baseUrl = new URL('https://api.nylas.com/v3/grants/grant-id/events');
681+
const queryParams = {
682+
calendarId: 'primary',
683+
684+
eventType: ['default' as const, 'outOfOffice' as const],
685+
};
686+
687+
const realApiClient = new APIClient({
688+
apiKey: 'test-api-key',
689+
apiUri: 'https://api.nylas.com',
690+
timeout: 30,
691+
headers: {},
692+
});
693+
694+
const setQueryStrings = (realApiClient as any).setQueryStrings.bind(realApiClient);
695+
const finalUrl = setQueryStrings(baseUrl, queryParams);
696+
const requestUrl = finalUrl.toString();
697+
698+
// Verify array parameters are handled correctly
699+
expect(requestUrl).toContain('?'); // Should have proper query separator
700+
expect(requestUrl).not.toContain('%3F'); // Should not have encoded question mark
701+
expect(requestUrl).toContain('attendees=user1%40example.com');
702+
expect(requestUrl).toContain('attendees=user2%40example.com');
703+
expect(requestUrl).toContain('event_type=default');
704+
expect(requestUrl).toContain('event_type=outOfOffice');
705+
});
706+
707+
it('should handle complex metadata pairs correctly', async () => {
708+
const baseUrl = new URL('https://api.nylas.com/v3/grants/grant-id/events');
709+
const queryParams = {
710+
calendarId: 'primary',
711+
metadataPair: {
712+
'key with spaces': 'value with & symbols',
713+
'another-key': 'another-value',
714+
'special-chars': 'value with ? and = signs'
715+
},
716+
};
717+
718+
const realApiClient = new APIClient({
719+
apiKey: 'test-api-key',
720+
apiUri: 'https://api.nylas.com',
721+
timeout: 30,
722+
headers: {},
723+
});
724+
725+
const setQueryStrings = (realApiClient as any).setQueryStrings.bind(realApiClient);
726+
const finalUrl = setQueryStrings(baseUrl, queryParams);
727+
const requestUrl = finalUrl.toString();
728+
729+
// Verify metadata pairs are handled correctly
730+
expect(requestUrl).toContain('?'); // Should have proper query separator
731+
expect(requestUrl).not.toContain('%3F'); // Should not have encoded question mark
732+
expect(requestUrl).toContain('metadata_pair=key%20with%20spaces%3Avalue%20with%20%26%20symbols');
733+
expect(requestUrl).toContain('metadata_pair=another-key%3Aanother-value');
734+
expect(requestUrl).toContain('metadata_pair=special-chars%3Avalue%20with%20%3F%20and%20%3D%20signs');
735+
});
736+
});
591737
});

0 commit comments

Comments
 (0)