mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-08-08 06:55:19 +02:00
Fixed unit, e2e and playwright tests
This commit is contained in:
parent
965e6ccd50
commit
4f4744eddc
6 changed files with 104 additions and 41 deletions
13
components.d.ts
vendored
13
components.d.ts
vendored
|
@ -92,19 +92,28 @@ declare module '@vue/runtime-core' {
|
||||||
HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
|
HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
|
||||||
IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default']
|
IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default']
|
||||||
'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default']
|
'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default']
|
||||||
|
'IconMdi:contentCopy': typeof import('~icons/mdi/content-copy')['default']
|
||||||
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
|
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
|
||||||
|
IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default']
|
||||||
IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default']
|
IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default']
|
||||||
|
IconMdiCamera: typeof import('~icons/mdi/camera')['default']
|
||||||
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
|
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
|
||||||
IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
|
IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
|
||||||
IconMdiClose: typeof import('~icons/mdi/close')['default']
|
IconMdiClose: typeof import('~icons/mdi/close')['default']
|
||||||
IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
|
IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
|
||||||
|
IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
|
||||||
|
IconMdiDownload: typeof import('~icons/mdi/download')['default']
|
||||||
IconMdiEye: typeof import('~icons/mdi/eye')['default']
|
IconMdiEye: typeof import('~icons/mdi/eye')['default']
|
||||||
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
|
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
|
||||||
IconMdiHeart: typeof import('~icons/mdi/heart')['default']
|
IconMdiHeart: typeof import('~icons/mdi/heart')['default']
|
||||||
|
IconMdiPause: typeof import('~icons/mdi/pause')['default']
|
||||||
|
IconMdiPlay: typeof import('~icons/mdi/play')['default']
|
||||||
|
IconMdiRecord: typeof import('~icons/mdi/record')['default']
|
||||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
||||||
IconMdiSearch: typeof import('~icons/mdi/search')['default']
|
IconMdiSearch: typeof import('~icons/mdi/search')['default']
|
||||||
IconMdiTranslate: typeof import('~icons/mdi/translate')['default']
|
IconMdiTranslate: typeof import('~icons/mdi/translate')['default']
|
||||||
IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default']
|
IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default']
|
||||||
|
IconMdiVideo: typeof import('~icons/mdi/video')['default']
|
||||||
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
|
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
|
||||||
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
|
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
|
||||||
Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
|
Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
|
||||||
|
@ -141,6 +150,7 @@ declare module '@vue/runtime-core' {
|
||||||
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
|
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
|
||||||
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||||
|
NDatePicker: typeof import('naive-ui')['NDatePicker']
|
||||||
NDivider: typeof import('naive-ui')['NDivider']
|
NDivider: typeof import('naive-ui')['NDivider']
|
||||||
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
||||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||||
|
@ -149,6 +159,7 @@ declare module '@vue/runtime-core' {
|
||||||
NGi: typeof import('naive-ui')['NGi']
|
NGi: typeof import('naive-ui')['NGi']
|
||||||
NGrid: typeof import('naive-ui')['NGrid']
|
NGrid: typeof import('naive-ui')['NGrid']
|
||||||
NH1: typeof import('naive-ui')['NH1']
|
NH1: typeof import('naive-ui')['NH1']
|
||||||
|
NH2: typeof import('naive-ui')['NH2']
|
||||||
NH3: typeof import('naive-ui')['NH3']
|
NH3: typeof import('naive-ui')['NH3']
|
||||||
NIcon: typeof import('naive-ui')['NIcon']
|
NIcon: typeof import('naive-ui')['NIcon']
|
||||||
NImage: typeof import('naive-ui')['NImage']
|
NImage: typeof import('naive-ui')['NImage']
|
||||||
|
@ -162,9 +173,11 @@ declare module '@vue/runtime-core' {
|
||||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
NSlider: typeof import('naive-ui')['NSlider']
|
NSlider: typeof import('naive-ui')['NSlider']
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import('naive-ui')['NSpace']
|
||||||
|
NSpin: typeof import('naive-ui')['NSpin']
|
||||||
NStatistic: typeof import('naive-ui')['NStatistic']
|
NStatistic: typeof import('naive-ui')['NStatistic']
|
||||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||||
NTable: typeof import('naive-ui')['NTable']
|
NTable: typeof import('naive-ui')['NTable']
|
||||||
|
NTag: typeof import('naive-ui')['NTag']
|
||||||
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
|
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
|
||||||
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
|
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
|
||||||
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
|
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
|
||||||
|
|
|
@ -13,8 +13,15 @@ test.describe('Tool - Epoch converter', () => {
|
||||||
await page.getByPlaceholder('Enter epoch timestamp').fill('1750452480');
|
await page.getByPlaceholder('Enter epoch timestamp').fill('1750452480');
|
||||||
await page.getByRole('button', { name: 'Convert to Date' }).click();
|
await page.getByRole('button', { name: 'Convert to Date' }).click();
|
||||||
|
|
||||||
await expect(page.getByText('GMT (UTC): Fri, 20 Jun 2025 20:48:00 GMT')).toBeVisible();
|
const utcLine = page.locator('text=GMT (UTC):');
|
||||||
await expect(page.getByText('Local Time: Fri, 20 Jun 2025, 13:48:00 GMT-7')).toBeVisible();
|
const localLine = page.locator('text=Local Time:');
|
||||||
|
|
||||||
|
await expect(utcLine).toContainText('GMT (UTC): Fri, 20 Jun 2025 20:48:00 GMT');
|
||||||
|
// await expect(localLine).toContainText('Local Time: Fri, Jun 20, 2025, 22:48:00 GMT+2');
|
||||||
|
await expect(localLine).toContainText('Local Time:');
|
||||||
|
await expect(localLine).toContainText('Jun 20, 2025');
|
||||||
|
await expect(localLine).toContainText('22:48:00');
|
||||||
|
await expect(localLine).toContainText('GMT+2');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Converts known date to epoch timestamp', async ({ page }) => {
|
test('Converts known date to epoch timestamp', async ({ page }) => {
|
||||||
|
@ -25,44 +32,63 @@ test.describe('Tool - Epoch converter', () => {
|
||||||
await page.getByPlaceholder('MM').nth(1).fill('48');
|
await page.getByPlaceholder('MM').nth(1).fill('48');
|
||||||
await page.getByPlaceholder('SS').fill('00');
|
await page.getByPlaceholder('SS').fill('00');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Convert to Epoch' }).click();
|
await page.getByRole('button', { name: 'Convert to Epoch (Local)' }).click();
|
||||||
|
|
||||||
await expect(page.getByText('1750452480')).toBeVisible();
|
await expect(page.getByText('1750420080')).toBeVisible({ timeout: 50000 });
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Convert to Epoch (UTC)' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByText('1750427280')).toBeVisible({ timeout: 50000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Shows error if year is not 4 digits', async ({ page }) => {
|
test('Shows error if year is not 4 digits', async ({ page }) => {
|
||||||
await page.getByPlaceholder('YYYY').fill('99');
|
await page.getByPlaceholder('YYYY').fill('99');
|
||||||
await page.getByRole('button', { name: 'Convert to Epoch (Local)' }).click();
|
await page.getByRole('button', { name: 'Convert to Epoch (Local)' }).click();
|
||||||
await expect(page.getByText('Year must be 4 digits')).toBeVisible();
|
await expect(page.getByText('Year must be 4 digits')).toBeVisible({ timeout: 50000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Shows error if month is invalid', async ({ page }) => {
|
test('Shows error if month is invalid', async ({ page }) => {
|
||||||
|
await page.getByPlaceholder('YYYY').fill('1999');
|
||||||
await page.getByPlaceholder('MM').first().fill('00');
|
await page.getByPlaceholder('MM').first().fill('00');
|
||||||
await page.getByRole('button', { name: 'Convert to Epoch (Local)' }).click();
|
await page.getByRole('button', { name: 'Convert to Epoch (Local)' }).click();
|
||||||
await expect(page.getByText('Month must be between 1 and 12')).toBeVisible();
|
await expect(page.getByText('Month must be between 1 and 12')).toBeVisible({ timeout: 50000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Shows error if day is invalid', async ({ page }) => {
|
test('Shows error if day is invalid', async ({ page }) => {
|
||||||
|
await page.getByPlaceholder('YYYY').fill('1999');
|
||||||
|
await page.getByPlaceholder('MM').first().fill('01');
|
||||||
await page.getByPlaceholder('DD').fill('0');
|
await page.getByPlaceholder('DD').fill('0');
|
||||||
await page.getByRole('button', { name: 'Convert to Epoch (UTC)' }).click();
|
await page.getByRole('button', { name: 'Convert to Epoch (UTC)' }).click();
|
||||||
await expect(page.getByText('Day must be between 1 and 31')).toBeVisible();
|
await expect(page.getByText('Day must be between 1 and 31')).toBeVisible({ timeout: 50000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Shows error if hour is invalid', async ({ page }) => {
|
test('Shows error if hour is invalid', async ({ page }) => {
|
||||||
|
await page.getByPlaceholder('YYYY').fill('1999');
|
||||||
|
await page.getByPlaceholder('MM').first().fill('01');
|
||||||
|
await page.getByPlaceholder('DD').fill('1');
|
||||||
await page.getByPlaceholder('HH').fill('24');
|
await page.getByPlaceholder('HH').fill('24');
|
||||||
await page.getByRole('button', { name: 'Convert to Epoch (Local)' }).click();
|
await page.getByRole('button', { name: 'Convert to Epoch (Local)' }).click();
|
||||||
await expect(page.getByText('Hour must be between 0 and 23')).toBeVisible();
|
await expect(page.getByText('Hour must be between 0 and 23')).toBeVisible({ timeout: 50000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Shows error if minute is invalid', async ({ page }) => {
|
test('Shows error if minute is invalid', async ({ page }) => {
|
||||||
await page.getByPlaceholder('MM').nth(1).fill('61');
|
await page.getByPlaceholder('YYYY').fill('1999');
|
||||||
|
await page.getByPlaceholder('MM').first().fill('01');
|
||||||
|
await page.getByPlaceholder('DD').fill('1');
|
||||||
|
await page.getByPlaceholder('HH').fill('23');
|
||||||
|
await page.getByPlaceholder('MM').nth(1).fill('60');
|
||||||
await page.getByRole('button', { name: 'Convert to Epoch (UTC)' }).click();
|
await page.getByRole('button', { name: 'Convert to Epoch (UTC)' }).click();
|
||||||
await expect(page.getByText('Minute must be between 0 and 59')).toBeVisible();
|
await expect(page.getByText('Minute must be between 0 and 59')).toBeVisible({ timeout: 50000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Shows error if second is invalid', async ({ page }) => {
|
test('Shows error if second is invalid', async ({ page }) => {
|
||||||
|
await page.getByPlaceholder('YYYY').fill('1999');
|
||||||
|
await page.getByPlaceholder('MM').first().fill('01');
|
||||||
|
await page.getByPlaceholder('DD').fill('1');
|
||||||
|
await page.getByPlaceholder('HH').fill('23');
|
||||||
|
await page.getByPlaceholder('MM').nth(1).fill('59');
|
||||||
await page.getByPlaceholder('SS').fill('99');
|
await page.getByPlaceholder('SS').fill('99');
|
||||||
await page.getByRole('button', { name: 'Convert to Epoch (UTC)' }).click();
|
await page.getByRole('button', { name: 'Convert to Epoch (UTC)' }).click();
|
||||||
await expect(page.getByText('Second must be between 0 and 59')).toBeVisible();
|
await expect(page.getByText('Second must be between 0 and 59')).toBeVisible({ timeout: 50000 });
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,18 +1,17 @@
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import { type DateParts, dateToEpoch, epochToDate, getISODateString } from './epoch-converter.service';
|
import { type DateParts, dateToEpoch, epochToDate, getISODateString } from '../epoch-converter.service';
|
||||||
|
|
||||||
process.env.TZ = 'America/Vancouver';
|
process.env.TZ = 'America/Vancouver';
|
||||||
|
|
||||||
describe('epochToDate', () => {
|
describe('epochToDate', () => {
|
||||||
it('converts known epoch seconds to correct formatted date (America/Vancouver)', () => {
|
it('converts known epoch seconds to correct formatted date (America/Vancouver)', () => {
|
||||||
const epoch = 1750707060;
|
const epoch = 1750707060;
|
||||||
const expectedUTC = 'Mon, 23 Jun 2025 19:31:00 GMT';
|
const expectedUTC = 'Mon, Jun 23, 2025, 19:31:00 UTC';
|
||||||
const expectedLocal = 'Mon, Jun 23, 2025, 12:31:00 PDT';
|
const expectedLocal = 'Mon, Jun 23, 2025, 12:31:00 PDT';
|
||||||
|
|
||||||
const result = epochToDate(epoch, {
|
const result = epochToDate(epoch, {
|
||||||
timeZone: 'America/Vancouver',
|
timeZone: 'America/Vancouver',
|
||||||
locale: 'en-US',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.local).toBe(expectedLocal);
|
expect(result.local).toBe(expectedLocal);
|
||||||
|
@ -29,8 +28,8 @@ describe('epochToDate', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('dateToEpoch', () => {
|
describe('dateToEpoch', () => {
|
||||||
it('converts a known local date to correct epoch (2025-06-20 13:48:00)', () => {
|
it('converts a known local date to correct epoch (2025-06-20 13:48:00) with timezone offset', () => {
|
||||||
const input = '2025-06-20T13:48:00';
|
const input = '2025-06-20T13:48:00-07:00';
|
||||||
|
|
||||||
const expectedEpoch = 1750452480;
|
const expectedEpoch = 1750452480;
|
||||||
const result = dateToEpoch(input);
|
const result = dateToEpoch(input);
|
||||||
|
@ -59,12 +58,11 @@ describe('epochToDate - Year 2038 boundary', () => {
|
||||||
|
|
||||||
const result = epochToDate(epoch, {
|
const result = epochToDate(epoch, {
|
||||||
timeZone: 'America/Vancouver',
|
timeZone: 'America/Vancouver',
|
||||||
locale: 'en-US',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const expectedLocal = 'Mon, Jan 18, 2038, 19:14:07 PST';
|
const expectedLocal = 'Mon, Jan 18, 2038, 19:14:07 PST';
|
||||||
|
|
||||||
const expectedUTC = 'Tue, 19 Jan 2038 03:14:07 GMT';
|
const expectedUTC = 'Tue, Jan 19, 2038, 03:14:07 UTC';
|
||||||
|
|
||||||
expect(result.local).toBe(expectedLocal);
|
expect(result.local).toBe(expectedLocal);
|
||||||
expect(result.utc).toBe(expectedUTC);
|
expect(result.utc).toBe(expectedUTC);
|
||||||
|
@ -75,12 +73,11 @@ describe('epochToDate - Year 2038 boundary', () => {
|
||||||
|
|
||||||
const result = epochToDate(epoch, {
|
const result = epochToDate(epoch, {
|
||||||
timeZone: 'America/Vancouver',
|
timeZone: 'America/Vancouver',
|
||||||
locale: 'en-US',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const expectedLocal = 'Mon, Jan 18, 2038, 19:14:08 PST';
|
const expectedLocal = 'Mon, Jan 18, 2038, 19:14:08 PST';
|
||||||
|
|
||||||
const expectedUTC = 'Tue, 19 Jan 2038 03:14:08 GMT';
|
const expectedUTC = 'Tue, Jan 19, 2038, 03:14:08 UTC';
|
||||||
|
|
||||||
expect(result.local).toBe(expectedLocal);
|
expect(result.local).toBe(expectedLocal);
|
||||||
expect(result.utc).toBe(expectedUTC);
|
expect(result.utc).toBe(expectedUTC);
|
|
@ -14,12 +14,12 @@ export interface DateParts {
|
||||||
* Converts a Unix epoch timestamp (in seconds or milliseconds) to a human-readable date.
|
* Converts a Unix epoch timestamp (in seconds or milliseconds) to a human-readable date.
|
||||||
*
|
*
|
||||||
* @param epoch - The epoch timestamp to convert (number or string).
|
* @param epoch - The epoch timestamp to convert (number or string).
|
||||||
* @param options - Optional locale and timeZone settings for local time formatting.
|
* @param options - Optional timeZone setting for local time formatting.
|
||||||
* @returns An object with both the local formatted string and UTC string.
|
* @returns An object with both the local formatted string and UTC string.
|
||||||
*/
|
*/
|
||||||
export function epochToDate(
|
export function epochToDate(
|
||||||
epoch: string | number,
|
epoch: string | number,
|
||||||
options?: { timeZone?: string; locale?: string },
|
options?: { timeZone?: string },
|
||||||
): { local: string; utc: string } {
|
): { local: string; utc: string } {
|
||||||
const num = typeof epoch === 'string' ? Number.parseInt(epoch, 10) : epoch;
|
const num = typeof epoch === 'string' ? Number.parseInt(epoch, 10) : epoch;
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ export function epochToDate(
|
||||||
|
|
||||||
const date = new Date(timestampInMs);
|
const date = new Date(timestampInMs);
|
||||||
|
|
||||||
const local = date.toLocaleString(options?.locale || 'en-US', {
|
const formatOptions: Intl.DateTimeFormatOptions = {
|
||||||
timeZone: options?.timeZone,
|
timeZoneName: 'short',
|
||||||
weekday: 'short',
|
weekday: 'short',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
|
@ -44,12 +44,22 @@ export function epochToDate(
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
second: '2-digit',
|
second: '2-digit',
|
||||||
hour12: false,
|
hour12: false,
|
||||||
timeZoneName: 'short',
|
};
|
||||||
|
|
||||||
|
const localFormatter = new Intl.DateTimeFormat('en-US', {
|
||||||
|
...formatOptions,
|
||||||
|
timeZone: options?.timeZone,
|
||||||
});
|
});
|
||||||
|
|
||||||
const utc = date.toUTCString();
|
const utcFormatter = new Intl.DateTimeFormat('en-US', {
|
||||||
|
...formatOptions,
|
||||||
|
timeZone: 'UTC',
|
||||||
|
});
|
||||||
|
|
||||||
return { local, utc };
|
return {
|
||||||
|
local: localFormatter.format(date),
|
||||||
|
utc: utcFormatter.format(date),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,13 +75,29 @@ export function dateToEpoch(
|
||||||
parseAsUTC?: boolean // if true, the date string will be parsed as UTC
|
parseAsUTC?: boolean // if true, the date string will be parsed as UTC
|
||||||
},
|
},
|
||||||
): number {
|
): number {
|
||||||
const shouldNormalizeToUTC = options?.parseAsUTC === true && !dateString.endsWith('Z');
|
const { parseAsUTC } = options ?? {};
|
||||||
const normalizedDateString = shouldNormalizeToUTC
|
|
||||||
? `${dateString}Z`
|
let normalizedDateString: string = dateString;
|
||||||
: dateString;
|
if (parseAsUTC && !dateString.endsWith('Z')) {
|
||||||
|
normalizedDateString = `${dateString}Z`;
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`test = ${normalizedDateString}`);
|
||||||
|
// else {
|
||||||
|
// // Manually compute local timezone offset and append it
|
||||||
|
// const tempDate = new Date(`${dateString}`);
|
||||||
|
// const offsetMinutes = tempDate.getTimezoneOffset();
|
||||||
|
// const sign = offsetMinutes <= 0 ? '+' : '-';
|
||||||
|
// const absOffset = Math.abs(offsetMinutes);
|
||||||
|
// const hours = String(Math.floor(absOffset / 60)).padStart(2, '0');
|
||||||
|
// const minutes = String(absOffset % 60).padStart(2, '0');
|
||||||
|
// const offset = `${sign}${hours}:${minutes}`;
|
||||||
|
// normalizedDateString = `${dateString}${offset}`;
|
||||||
|
// }
|
||||||
|
|
||||||
const date = new Date(normalizedDateString);
|
const date = new Date(normalizedDateString);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(date);
|
||||||
if (Number.isNaN(date.getTime())) {
|
if (Number.isNaN(date.getTime())) {
|
||||||
throw new TypeError('Invalid date string');
|
throw new TypeError('Invalid date string');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { type DateParts, dateToEpoch, epochToDate, getISODateString } from './epoch-converter.service.ts';
|
import { type DateParts, dateToEpoch, epochToDate, getISODateString } from './epoch-converter.service';
|
||||||
|
|
||||||
const epochInput = ref('');
|
const epochInput = ref('');
|
||||||
const dateOutput = ref<{ local: string; utc: string } | null>(null);
|
const dateOutput = ref<{ local: string; utc: string } | null>(null);
|
||||||
|
@ -41,7 +41,7 @@ function convertDateToEpochLocal() {
|
||||||
try {
|
try {
|
||||||
validateDateParts(dateParts.value);
|
validateDateParts(dateParts.value);
|
||||||
const isoString = getISODateString(dateParts.value);
|
const isoString = getISODateString(dateParts.value);
|
||||||
epochOutput.value = dateToEpoch(isoString);
|
epochOutput.value = dateToEpoch(isoString).toString();
|
||||||
dateInputError.value = null;
|
dateInputError.value = null;
|
||||||
}
|
}
|
||||||
catch (e: any) {
|
catch (e: any) {
|
||||||
|
@ -57,7 +57,7 @@ function convertDateToEpochUTC() {
|
||||||
try {
|
try {
|
||||||
validateDateParts(dateParts.value);
|
validateDateParts(dateParts.value);
|
||||||
const isoString = getISODateString(dateParts.value);
|
const isoString = getISODateString(dateParts.value);
|
||||||
epochOutput.value = dateToEpoch(isoString, { utc: true });
|
epochOutput.value = dateToEpoch(isoString, { parseAsUTC: true }).toString();
|
||||||
dateInputError.value = null;
|
dateInputError.value = null;
|
||||||
}
|
}
|
||||||
catch (e: any) {
|
catch (e: any) {
|
||||||
|
|
|
@ -12,20 +12,21 @@ test.describe('Tool - Gzip decompressor', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Decompresses valid base64 string and shows output', async ({ page }) => {
|
test('Decompresses valid base64 string and shows output', async ({ page }) => {
|
||||||
const input = page.getByLabel('GZipped User Input');
|
const input = page.getByPlaceholder('Paste your GZipped string here...');
|
||||||
const output = page.getByLabel('Decompressed Output');
|
const output = page.locator('textarea[readonly]');
|
||||||
|
|
||||||
await input.fill(validGzipBase64);
|
await input.fill(validGzipBase64);
|
||||||
|
|
||||||
await expect(output).toHaveValue('Hello World');
|
// Wait for the output text to contain 'Hello World'
|
||||||
|
await expect(output).toHaveValue('Hello World', { timeout: 30000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Shows error for invalid input', async ({ page }) => {
|
test('Shows error for invalid input', async ({ page }) => {
|
||||||
const input = page.getByLabel('GZipped User Input');
|
const input = page.getByPlaceholder('Paste your GZipped string here...');
|
||||||
|
|
||||||
|
await expect(input).toBeVisible();
|
||||||
await input.fill('invalid-base64');
|
await input.fill('invalid-base64');
|
||||||
|
|
||||||
const alert = page.getByRole('alert');
|
await expect(page.getByText('Decompression failed. Please ensure the input is valid GZip.')).toBeVisible();
|
||||||
await expect(alert).toContainText('Decompression failed');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue