Back to Repositories

Testing URL Manipulation and Pattern Matching in Insomnia SDK

This test suite validates URL manipulation and pattern matching functionality in the Insomnia SDK. It thoroughly tests URL parsing, query parameter handling, and URL pattern matching capabilities essential for API testing and request handling.

Test Coverage Overview

The test suite provides comprehensive coverage of URL-related functionality:
  • URL parsing and manipulation with query parameters, auth, and path components
  • Query parameter handling including parsing, formatting, and modification
  • URL pattern matching with protocol, host, port, and path validation
  • Edge cases including internal URLs, IP addresses, and template variables

Implementation Analysis

The testing approach uses Jest/Vitest framework features for structured testing:
  • Organized test suites using describe/it blocks for logical grouping
  • Extensive use of expect assertions for validation
  • Test case iteration for URL parsing scenarios
  • Modular test structure separating URL and pattern matching tests

Technical Details

Testing infrastructure and setup:
  • Vitest as the primary testing framework
  • TypeScript for type-safe testing
  • Custom URL and QueryParam classes for URL manipulation
  • UrlMatchPattern class for URL pattern validation

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Comprehensive test cases covering both positive and negative scenarios
  • Clear test descriptions and organization
  • Isolated test cases for different functionality
  • Thorough validation of object methods and properties

kong/insomnia

packages/insomnia-sdk/src/objects/__tests__/urls.test.ts

            
import { describe, expect, it } from 'vitest';

import { QueryParam, Url, UrlMatchPattern } from '../urls';
import { Variable } from '../variables';

describe('test Url object', () => {
    it('test QueryParam', () => {
        const queryParam = new QueryParam({
            key: 'uname',
            value: 'patrick star',
        });

        expect(queryParam.toString()).toEqual('uname=patrick+star');

        queryParam.update('uname=peter+parker');
        expect(queryParam.toString()).toEqual('uname=peter+parker');

        expect(
            QueryParam.unparseSingle({ key: 'uname', value: 'patrick star' })
        ).toEqual('uname=patrick+star');

        expect(
            QueryParam.unparse({ uname: 'patrick star', password: '123' })
        ).toEqual('uname=patrick+star&password=123');

        expect(
            QueryParam.parseSingle('uname=patrick+star')
        ).toEqual({ key: 'uname', value: 'patrick star' });

        expect(
            QueryParam.parse('uname=patrick+star&password=123')
        ).toEqual([{ 'key': 'uname', 'value': 'patrick star' }, { 'key': 'password', 'value': '123' }]);
    });

    it('test Url methods', () => {
        const url = new Url({
            auth: {
                username: 'usernameValue',
                password: 'passwordValue',
            },
            hash: 'hashValue',
            host: ['hostValue', 'com'],
            path: ['pathLevel1', 'pathLevel2'],
            port: '777',
            protocol: 'https:',
            query: [
                new QueryParam({ key: 'key1', value: 'value1' }),
                new QueryParam({ key: 'key2', value: 'value2' }),
                new QueryParam({ key: 'key3', value: 'value3' }),
            ],
            variables: [
                new Variable({ key: 'varKey', value: 'varValue' }),
            ],
        });

        expect(url.getHost()).toEqual('hostValue.com');
        expect(url.getPath()).toEqual('/pathLevel1/pathLevel2');

        expect(url.getQueryString()).toEqual('key1=value1&key2=value2&key3=value3');
        expect(url.getPathWithQuery()).toEqual('/pathLevel1/pathLevel2?key1=value1&key2=value2&key3=value3');
        expect(url.getRemote(true)).toEqual('hostValue.com:777');
        expect(url.getRemote(false)).toEqual('hostValue.com:777'); // TODO: add more cases

        url.removeQueryParams([
            new QueryParam({ key: 'key1', value: 'value1' }),
        ]);
        url.removeQueryParams('key3');
        expect(url.getQueryString()).toEqual('key2=value2');
        expect(url.toString()).toEqual('https://usernameValue:[email protected]:777/pathLevel1/pathLevel2?key2=value2#hashValue');

        const url2 = new Url('https://usernameValue:[email protected]:777/pathLevel1/pathLevel2?key1=value1&key2=value2#hashValue');
        expect(url2.getHost()).toEqual('hostValue.com');
        expect(url2.getPath()).toEqual('/pathLevel1/pathLevel2');
        expect(url2.getQueryString()).toEqual('key1=value1&key2=value2');
        expect(url2.getPathWithQuery()).toEqual('/pathLevel1/pathLevel2?key1=value1&key2=value2');
        expect(url2.getRemote(true)).toEqual('hostValue.com:777');
        expect(url2.getRemote(false)).toEqual('hostValue.com:777'); // TODO: add more cases

        url2.removeQueryParams([
            new QueryParam({ key: 'key1', value: 'value1' }),
        ]);
        expect(url2.getQueryString()).toEqual('key2=value2');
        expect(url2.toString()).toEqual('https://usernameValue:[email protected]:777/pathLevel1/pathLevel2?key2=value2#hashValue');
    });

    it('test Url static methods', () => {
        // static methods
        const urlStr = 'https://myhost.com/path1/path2';
        const urlOptions = Url.parse(urlStr);
        const urlObj = new Url(urlOptions || '');

        expect(urlObj.toString()).toEqual(urlStr);
    });

    const urlParsingTests = [
        {
            testName: 'interal url',
            url: 'inso/',
        },
        {
            testName: 'interal url with protocol',
            url: 'http://inso/',
        },
        {
            testName: 'interal url with auth',
            url: 'http://name:pwd@inso/',
        },
        {
            testName: 'interal url with auth without protocol',
            url: 'name:pwd@inso/',
        },
        {
            testName: 'ip address',
            url: 'http://127.0.0.1/',
        },
        {
            testName: 'localhost',
            url: 'https://localhost/',
        },
        {
            testName: 'url with query params',
            url: 'localhost/?k=v',
        },
        {
            testName: 'url with hash',
            url: 'localhost/#myHash',
        },
        {
            testName: 'url with query params and hash',
            url: 'localhost/?k=v#myHash',
        },
        {
            testName: 'url with query params and hash',
            url: 'localhost/?k={{ myValue }}',
        },
        {
            testName: 'url with query params and hash',
            url: 'localhost/#My{{ hashValue }}',
        },
        {
            testName: 'url with path params',
            url: 'inso.com/:path1/:path',
        },
        {
            testName: 'url with tags and path params',
            url: '{{ _.baseUrl }}/:path1/:path',
        },
        {
            testName: 'hybrid of path params and tags',
            url: '{{ baseUrl }}/:path_{{ _.pathSuffix }}',
        },
        {
            testName: '@ is used in path',
            url: '{{ baseUrl }}/[email protected]',
        },
        {
            testName: '@ is used in auth and path',
            url: 'user:[email protected]/[email protected]',
        },
        {
            testName: '@ is used in auth',
            url: 'user:[email protected]/',
        },
        {
            testName: '@ is used in path with path params, targs and hash',
            url: '{{ baseUrl }}/:path__{{ _.pathSuffix }}/[email protected]#hash',
        },
    ];

    urlParsingTests.forEach(testCase => {
        it(`parsing url: ${testCase.testName}`, () => {
            const urlObj = new Url(testCase.url);
            expect(urlObj.toString()).toEqual(testCase.url);
        });
    });
});

describe('test Url Match Pattern', () => {
    it('test UrlMatchPattern', () => {
        const pattern = 'http+https+custom://*.insomnia.com:80/p1/*';
        const matchPattern = new UrlMatchPattern(pattern);

        expect(matchPattern.getProtocols()).toEqual(['http', 'https', 'custom']);
        expect(matchPattern.testProtocol('http')).toBeTruthy();
        expect(matchPattern.testProtocol('https')).toBeTruthy();
        expect(matchPattern.testProtocol('custom')).toBeTruthy();
        expect(matchPattern.testProtocol('unmatched')).toBeFalsy();

        expect(matchPattern.testHost('download.insomnia.com')).toBeTruthy();
        expect(matchPattern.testHost('bin.download.insomnia.com')).toBeFalsy();
        expect(matchPattern.testHost('insomnia.com')).toBeFalsy();
        expect(matchPattern.testHost('com')).toBeFalsy();

        expect(matchPattern.testPath('/p1/abc')).toBeTruthy();
        expect(matchPattern.testPath('/p1/')).toBeTruthy();
        expect(matchPattern.testPath('/p1')).toBeFalsy();
        expect(matchPattern.testPath('/')).toBeFalsy();
        expect(matchPattern.testPath('')).toBeFalsy();

        expect(matchPattern.testPort('80', 'https')).toBeTruthy();
        expect(matchPattern.testPort('443', 'https')).toBeFalsy();
        expect(matchPattern.testPort('80', 'http')).toBeTruthy();
        expect(matchPattern.testPort('80', 'unmatched')).toBeFalsy();
    });

    it('test UrlMatchPattern with no protocol', () => {
        const pattern = '*.insomnia.com/p1/*';
        try {
            const matchPattern = new UrlMatchPattern(pattern);
            matchPattern.testProtocol('http');
        } catch (e: any) {
            expect(e.message).toContain('UrlMatchPattern: protocol is not specified');
        }
    });

    it('test UrlMatchPattern with no port', () => {
        const pattern = 'http+https+custom://*.insomnia.com/p1/*';
        const matchPattern = new UrlMatchPattern(pattern);

        expect(matchPattern.getProtocols()).toEqual(['http', 'https', 'custom']);
        expect(matchPattern.testProtocol('http')).toBeTruthy();
        expect(matchPattern.testProtocol('https')).toBeTruthy();
        expect(matchPattern.testProtocol('custom')).toBeTruthy();
        expect(matchPattern.testProtocol('unmatched')).toBeFalsy();

        expect(matchPattern.testHost('download.insomnia.com')).toBeTruthy();
        expect(matchPattern.testHost('bin.download.insomnia.com')).toBeFalsy();
        expect(matchPattern.testHost('insomnia.com')).toBeFalsy();
        expect(matchPattern.testHost('com')).toBeFalsy();

        expect(matchPattern.testPath('/p1/abc')).toBeTruthy();
        expect(matchPattern.testPath('/p1/')).toBeTruthy();
        expect(matchPattern.testPath('/p1')).toBeFalsy();
        expect(matchPattern.testPath('/')).toBeFalsy();
        expect(matchPattern.testPath('')).toBeFalsy();

        expect(matchPattern.testPort('443', 'https')).toBeTruthy();
        expect(matchPattern.testPort('80', 'http')).toBeTruthy();
        expect(matchPattern.testPort('443', 'http')).toBeFalsy();
        expect(matchPattern.testPort('80', 'https')).toBeFalsy();
    });

    it('test UrlMatchPattern with no path', () => {
        const pattern = 'http+https+custom://*.insomnia.com';
        const matchPattern = new UrlMatchPattern(pattern);

        expect(matchPattern.getProtocols()).toEqual(['http', 'https', 'custom']);
        expect(matchPattern.testProtocol('http')).toBeTruthy();
        expect(matchPattern.testProtocol('https')).toBeTruthy();
        expect(matchPattern.testProtocol('custom')).toBeTruthy();
        expect(matchPattern.testProtocol('unmatched')).toBeFalsy();

        expect(matchPattern.testHost('download.insomnia.com')).toBeTruthy();
        expect(matchPattern.testHost('bin.download.insomnia.com')).toBeFalsy();
        expect(matchPattern.testHost('insomnia.com')).toBeFalsy();
        expect(matchPattern.testHost('com')).toBeFalsy();

        expect(matchPattern.testPath('')).toBeTruthy();
        expect(matchPattern.testPath('/')).toBeFalsy(); // it is not handled temporarily

        expect(matchPattern.testPort('443', 'https')).toBeTruthy();
        expect(matchPattern.testPort('80', 'http')).toBeTruthy();
        expect(matchPattern.testPort('443', 'http')).toBeFalsy();
        expect(matchPattern.testPort('80', 'https')).toBeFalsy();
    });
});