Migrate url tooling to twenty-shared (#10440)
Migrate and unify URL tooling in twenty-shared. We now have: - isValidHostname which follows our own business rules - a zod schema that can be re-used in different context and leverages is isValidHostname - isValidUrl on top of the zod schema - a getAbsoluteURl and getHostname on top of the zod schema I have added a LOT of tests to cover all the cases I've found Also fixes: https://github.com/twentyhq/twenty/issues/10147
This commit is contained in:
@ -0,0 +1,34 @@
|
||||
import { absoluteUrlSchema } from '../absoluteUrlSchema';
|
||||
|
||||
describe('absoluteUrlSchema', () => {
|
||||
it('validates an absolute url', () => {
|
||||
expect(absoluteUrlSchema.parse('https://www.example.com')).toBe(
|
||||
'https://www.example.com',
|
||||
);
|
||||
expect(absoluteUrlSchema.parse('http://subdomain.example.com')).toBe(
|
||||
'http://subdomain.example.com',
|
||||
);
|
||||
expect(absoluteUrlSchema.parse('https://www.example.com/path')).toBe(
|
||||
'https://www.example.com/path',
|
||||
);
|
||||
expect(absoluteUrlSchema.parse('https://www.example.com?query=123')).toBe(
|
||||
'https://www.example.com?query=123',
|
||||
);
|
||||
expect(absoluteUrlSchema.parse('http://localhost:3000')).toBe(
|
||||
'http://localhost:3000',
|
||||
);
|
||||
});
|
||||
|
||||
it('transforms a non-absolute URL to an absolute URL', () => {
|
||||
expect(absoluteUrlSchema.parse('example.com')).toBe('https://example.com');
|
||||
expect(absoluteUrlSchema.parse('www.subdomain.example.com')).toBe(
|
||||
'https://www.subdomain.example.com',
|
||||
);
|
||||
});
|
||||
|
||||
it('fails for invalid urls', () => {
|
||||
expect(absoluteUrlSchema.safeParse('https://2').success).toBe(false);
|
||||
expect(absoluteUrlSchema.safeParse('?o').success).toBe(false);
|
||||
expect(absoluteUrlSchema.safeParse('\\').success).toBe(false);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,16 @@
|
||||
import { getAbsoluteUrlOrThrow } from 'src/utils/url/getAbsoluteUrlOrThrow';
|
||||
|
||||
describe('getAbsoluteUrlOrThrow', () => {
|
||||
it("returns the URL's hostname", () => {
|
||||
expect(getAbsoluteUrlOrThrow('https://www.example.com')).toBe(
|
||||
'https://www.example.com',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns an empty string for invalid URLs', () => {
|
||||
expect(() => getAbsoluteUrlOrThrow('?o')).toThrow('Invalid URL');
|
||||
expect(() => getAbsoluteUrlOrThrow('')).toThrow('Invalid URL');
|
||||
expect(() => getAbsoluteUrlOrThrow('\\')).toThrow('Invalid URL');
|
||||
expect(() => getAbsoluteUrlOrThrow('2')).toThrow('Invalid URL');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,30 @@
|
||||
import { getUrlHostnameOrThrow } from 'src/utils/url/getUrlHostnameOrThrow';
|
||||
|
||||
describe('getUrlHostnameOrThrow', () => {
|
||||
it("returns the URL's hostname", () => {
|
||||
expect(getUrlHostnameOrThrow('https://www.example.com')).toBe(
|
||||
'www.example.com',
|
||||
);
|
||||
expect(getUrlHostnameOrThrow('http://subdomain.example.com')).toBe(
|
||||
'subdomain.example.com',
|
||||
);
|
||||
expect(getUrlHostnameOrThrow('https://www.example.com/path')).toBe(
|
||||
'www.example.com',
|
||||
);
|
||||
expect(getUrlHostnameOrThrow('https://www.example.com?query=123')).toBe(
|
||||
'www.example.com',
|
||||
);
|
||||
expect(getUrlHostnameOrThrow('http://localhost:3000')).toBe('localhost');
|
||||
expect(getUrlHostnameOrThrow('example.com')).toBe('example.com');
|
||||
expect(getUrlHostnameOrThrow('www.subdomain.example.com')).toBe(
|
||||
'www.subdomain.example.com',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns an empty string for invalid URLs', () => {
|
||||
expect(() => getUrlHostnameOrThrow('?o')).toThrow('Invalid URL');
|
||||
expect(() => getUrlHostnameOrThrow('')).toThrow('Invalid URL');
|
||||
expect(() => getUrlHostnameOrThrow('\\')).toThrow('Invalid URL');
|
||||
expect(() => getUrlHostnameOrThrow('2')).toThrow('Invalid URL');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,71 @@
|
||||
import { isValidHostname } from 'src/utils/url/isValidHostname';
|
||||
|
||||
describe('isValidHostname', () => {
|
||||
it(`should return true if string google`, () => {
|
||||
expect(isValidHostname('google')).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return true if string google.com`, () => {
|
||||
expect(isValidHostname('google.com')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string bbc.co.uk`, () => {
|
||||
expect(isValidHostname('bbc.co.uk')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string www.subdomain.example.com`, () => {
|
||||
expect(isValidHostname('www.subdomain.example.com')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string web.io`, () => {
|
||||
expect(isValidHostname('web.io')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string x.com`, () => {
|
||||
expect(isValidHostname('x.com')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string 2.com`, () => {
|
||||
expect(isValidHostname('2.com')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string localhost`, () => {
|
||||
expect(isValidHostname('localhost')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string 127.0.0.1`, () => {
|
||||
expect(isValidHostname('127.0.0.1')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return false if string 2`, () => {
|
||||
expect(isValidHostname('2')).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return false if string contains non-valid characters`, () => {
|
||||
expect(isValidHostname('subdomain.example.com/path')).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return false if string is empty`, () => {
|
||||
expect(isValidHostname('')).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return false if string is one word`, () => {
|
||||
expect(isValidHostname('subdomain')).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return true if string is ip address`, () => {
|
||||
expect(isValidHostname('192.168.2.0')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return false if string is ip address but allowIp is false`, () => {
|
||||
expect(isValidHostname('192.168.2.0', { allowIp: false })).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return true if string is localhost but allowLocalhost is false`, () => {
|
||||
expect(isValidHostname('localhost', { allowLocalhost: false })).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return true if string is localhost but allowLocalhost is true`, () => {
|
||||
expect(isValidHostname('localhost', { allowLocalhost: true })).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,29 @@
|
||||
import { isValidUrl } from '../isValidUrl';
|
||||
|
||||
describe('isValidUrl', () => {
|
||||
it('test cases', () => {
|
||||
// Truthy
|
||||
expect(isValidUrl('https://www.example.com')).toBe(true);
|
||||
expect(isValidUrl('http://192.168.2.0:3000')).toBe(true);
|
||||
expect(isValidUrl('http://localhost')).toBe(true);
|
||||
expect(isValidUrl('http://localhost:3000')).toBe(true);
|
||||
expect(isValidUrl('http://subdomain.example.com')).toBe(true);
|
||||
expect(isValidUrl('https://www.example.com/path')).toBe(true);
|
||||
expect(isValidUrl('https://www.example.com/path/path2?query=123')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(isValidUrl('http://localhost:3000')).toBe(true);
|
||||
expect(isValidUrl('example.com')).toBe(true);
|
||||
expect(isValidUrl('www.subdomain.example.com')).toBe(true);
|
||||
expect(isValidUrl('192.168.2.0')).toBe(true);
|
||||
expect(isValidUrl('3.com')).toBe(true);
|
||||
|
||||
// Falsy
|
||||
expect(isValidUrl('?o')).toBe(false);
|
||||
expect(isValidUrl('')).toBe(false);
|
||||
expect(isValidUrl('\\')).toBe(false);
|
||||
expect(isValidUrl('wwwexamplecom')).toBe(false);
|
||||
expect(isValidUrl('2/toto')).toBe(false);
|
||||
expect(isValidUrl('2')).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user