bewcloud/public/ts/utils/misc_test.ts
Bruno Bernardino c26cae625e
Remove fresh
This implements a huge change, where Fresh is removed as a framework and serving files, allowing more control over importing, bundling, and serving files and components.

The biggest challenge was to continue making sure that there weren't too many places to look into for import versions, and `PasswordlessPasskeyLogin.tsx` became a prototype in migrating a component to fully SSR, no need for frontend parsing (via Babel) or bundling (via a custom-script, downloading frontend dependencies from esm.sh). Still, there are too many components to migrate like that, and it's all working, so I likely won't even attempt it unless there's some bug, new feature, or security vulnerability to address that warrants a rewrite of those.

This also updates all dependencies (except `@libs/xml` because that still causes some breaking in DAV endpoints), including Deno!

All other advantages can be seen in the related issues, and the breaking change this (v4.0.0) introduces is related simply to `config.email.tlsMode` (which had a deprecation warning throughout v3), and because, while I tested many things exhaustively, it's not impossible something broke that I didn't see.

Closes #141
Closes #132
2026-02-20 10:54:31 +00:00

314 lines
8.5 KiB
TypeScript

import { assertEquals } from '@std/assert';
import { SupportedCurrencySymbol } from '/lib/types.ts';
import {
convertFormDataToObject,
convertObjectToFormData,
escapeHtml,
formatInputToNumber,
formatNumber,
generateHash,
generateRandomCode,
isRunningLocally,
splitArrayInChunks,
validateEmail,
validateUrl,
} from './misc.ts';
Deno.test('that escapeHtml works', () => {
const tests: { input: string; expected: string }[] = [
{
input: '<a href="https://brunobernardino.com">URL</a>',
expected: '&lt;a href=&quot;https://brunobernardino.com&quot;&gt;URL&lt;/a&gt;',
},
{
input: "\"><img onerror='alert(1)' />",
expected: '&quot;&gt;&lt;img onerror=&#039;alert(1)&#039; /&gt;',
},
];
for (const test of tests) {
const output = escapeHtml(test.input);
assertEquals(output, test.expected);
}
});
Deno.test('that generateRandomCode works', () => {
const tests: { length: number }[] = [
{
length: 6,
},
{
length: 7,
},
{
length: 8,
},
];
for (const test of tests) {
const output = generateRandomCode(test.length);
assertEquals(output.length, test.length);
}
});
Deno.test('that splitArrayInChunks works', () => {
const tests: { input: { array: { number: number }[]; chunkLength: number }; expected: { number: number }[][] }[] = [
{
input: {
array: [
{ number: 1 },
{ number: 2 },
{ number: 3 },
{ number: 4 },
{ number: 5 },
{ number: 6 },
],
chunkLength: 2,
},
expected: [
[{ number: 1 }, { number: 2 }],
[{ number: 3 }, { number: 4 }],
[{ number: 5 }, { number: 6 }],
],
},
{
input: {
array: [
{ number: 1 },
{ number: 2 },
{ number: 3 },
{ number: 4 },
{ number: 5 },
],
chunkLength: 2,
},
expected: [
[{ number: 1 }, { number: 2 }],
[{ number: 3 }, { number: 4 }],
[{ number: 5 }],
],
},
{
input: {
array: [
{ number: 1 },
{ number: 2 },
{ number: 3 },
{ number: 4 },
{ number: 5 },
{ number: 6 },
],
chunkLength: 3,
},
expected: [
[{ number: 1 }, { number: 2 }, { number: 3 }],
[{ number: 4 }, { number: 5 }, { number: 6 }],
],
},
];
for (const test of tests) {
const output = splitArrayInChunks(
test.input.array,
test.input.chunkLength,
);
assertEquals(output, test.expected);
}
});
Deno.test('that generateHash works', async () => {
const tests: { input: { value: string; algorithm: string }; expected: string }[] = [
{
input: {
value: 'password',
algorithm: 'SHA-256',
},
expected: '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8',
},
{
input: {
value: '123456',
algorithm: 'SHA-256',
},
expected: '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92',
},
];
for (const test of tests) {
const output = await generateHash(test.input.value, test.input.algorithm);
assertEquals(output, test.expected);
}
});
Deno.test('that validateEmail works', () => {
const tests: { email: string; expected: boolean }[] = [
{ email: 'user@example.com', expected: true },
{ email: 'u@e.c', expected: true },
{ email: 'user@example.', expected: false },
{ email: '@example.com', expected: false },
{ email: 'user@example.', expected: false },
{ email: 'ABC', expected: false },
];
for (const test of tests) {
const result = validateEmail(test.email);
assertEquals(result, test.expected);
}
});
Deno.test('that validateUrl works', () => {
const tests: { url: string; expected: boolean }[] = [
{ url: 'https://bewcloud.com', expected: true },
{ url: 'ftp://something', expected: true },
{ url: 'http', expected: false },
{ url: 'https://', expected: false },
{ url: 'http://a', expected: true },
{ url: 'ABC', expected: false },
];
for (const test of tests) {
const result = validateUrl(test.url);
assertEquals(result, test.expected);
}
});
Deno.test('that convertFormDataToObject works', () => {
const formData1 = new FormData();
formData1.append('user', '1');
formData1.append('is_real', 'false');
formData1.append('tags', 'one');
formData1.append('tags', 'two');
const formData2 = new FormData();
formData2.append('user', '2');
formData2.append('is_real', 'true');
formData2.append('tags', 'one');
formData2.append('empty', '');
const tests: { input: FormData; expected: Record<string, any> }[] = [
{
input: formData1,
expected: {
user: '1',
is_real: 'false',
// tags: ['one', 'two'],
tags: 'two', // NOTE: This is a limitation of the simple logic, but it should ideally be the array above
},
},
{
input: formData2,
expected: {
user: '2',
is_real: 'true',
tags: 'one',
empty: '',
},
},
];
for (const test of tests) {
const output = convertFormDataToObject(test.input);
assertEquals(output, test.expected);
}
});
Deno.test('that convertObjectToFormData works', () => {
const formData1 = new FormData();
formData1.append('user', '1');
formData1.append('is_real', 'false');
formData1.append('tags', 'one');
// formData1.append('tags', 'two');// NOTE: This is a limitation of the simple logic, but it should ideally be an array below
const formData2 = new FormData();
formData2.append('user', '2');
formData2.append('is_real', 'true');
formData2.append('tags', 'one');
formData2.append('empty', '');
const tests: { input: Record<string, any>; expected: FormData }[] = [
{
input: {
user: '1',
is_real: 'false',
tags: 'one',
},
expected: formData1,
},
{
input: {
user: '2',
is_real: 'true',
tags: 'one',
empty: '',
},
expected: formData2,
},
];
for (const test of tests) {
const output = convertObjectToFormData(test.input);
assertEquals(convertFormDataToObject(output), convertFormDataToObject(test.expected));
}
});
Deno.test('that isRunningLocally works', () => {
const tests: { url: string; expected: boolean }[] = [
{ url: 'http://localhost:8000', expected: true },
{ url: 'http://127.0.0.1:8000', expected: true },
{ url: 'http://0.0.0.0:8000', expected: true },
{ url: 'http://10.0.0.1:8000', expected: true },
{ url: 'http://172.16.0.1:8000', expected: true },
{ url: 'http://192.168.0.1:8000', expected: true },
{ url: 'http://example.com', expected: false },
{ url: 'http://68.18.161.245:8000', expected: false },
{ url: 'https://example.com', expected: false },
{ url: 'http://2000.10.5000.1111', expected: false },
{ url: 'http://192.168.0.1', expected: true },
];
for (const test of tests) {
const request = { url: test.url } as Request;
const result = isRunningLocally(request);
assertEquals(result, test.expected);
}
});
Deno.test('that formatNumber works', () => {
const tests: { currency: SupportedCurrencySymbol; number: number; expected: string }[] = [
{ currency: '$', number: 10000, expected: '$10,000' },
{ currency: '$', number: 10000.5, expected: '$10,000.5' },
{ currency: '€', number: 10000, expected: '€10,000' },
{ currency: '€', number: 900.999, expected: '€901' },
{ currency: '€', number: 900.991, expected: '€900.99' },
{ currency: '$', number: 50.11, expected: '$50.11' },
{ currency: '£', number: 900.999, expected: '£901' },
{ currency: '£', number: 900.991, expected: '£900.99' },
{ currency: '£', number: 50.11, expected: '£50.11' },
];
for (const test of tests) {
const result = formatNumber(test.currency, test.number);
assertEquals(result, test.expected);
}
});
Deno.test('that formatInputToNumber works', () => {
const tests: { input: number | string; expected: number }[] = [
{ input: 42, expected: 42 },
{ input: '42', expected: 42 },
{ input: 42.5, expected: 42.5 },
{ input: '42.5', expected: 42.5 },
{ input: '42,5', expected: 42.5 },
{ input: '1234,56', expected: 1234.56 },
{ input: 0, expected: 0 },
{ input: '0', expected: 0 },
{ input: '0,0', expected: 0 },
{ input: '0.0', expected: 0 },
];
for (const test of tests) {
const result = formatInputToNumber(test.input);
assertEquals(result, test.expected);
}
});