-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
136 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
## Description | ||
|
||
Briefly describe the changes made in this Pull Request. | ||
|
||
## Additional context (optional) | ||
|
||
Add any additional context or information about the changes made in this PR. | ||
|
||
## How to test | ||
|
||
Provide clear and concise instructions on how to test the changes made in this PR. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
name: Build and Test 🏗️ | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
pull_request: | ||
branches: [main] | ||
|
||
jobs: | ||
build-and-deploy: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout code 📥 | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up Node.js ⚙️ | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: '20' | ||
cache: 'yarn' | ||
cache-dependency-path: yarn.lock | ||
|
||
- name: Install dependencies 📦 | ||
run: | | ||
HUSKY=0 yarn install --prefer-offline --frozen-lockfile | ||
- name: Lint code 🎨 | ||
run: | | ||
yarn lint | ||
- name: Build project 🏗️ | ||
run: | | ||
yarn build | ||
- name: Get number of CPU cores 💻 | ||
id: cpu-cores | ||
uses: SimenB/github-actions-cpu-cores@v2 | ||
|
||
- name: Run Unit tests 🧪 | ||
run: | | ||
yarn coverage --max-workers ${{ steps.cpu-cores.outputs.count }} | ||
- name: Upload coverage to Codecov 📊 | ||
uses: codecov/codecov-action@v3 | ||
env: | ||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,77 @@ | ||
import { describe, it, expect } from 'vitest'; | ||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; | ||
|
||
import { formatOCPDate } from '../src/console/core/utils/formatOCPDate'; | ||
import { ISO8601Timestamp } from '../src/console/interfaces/CRD_Base'; | ||
|
||
describe('formatOCPDate', () => { | ||
it('formats date correctly', () => { | ||
beforeEach(() => { | ||
vi.useFakeTimers(); | ||
vi.setSystemTime(new Date('2024-02-05T12:00:00Z')); | ||
}); | ||
|
||
afterEach(() => { | ||
vi.useRealTimers(); | ||
}); | ||
|
||
it('formats date with default locale and timezone', () => { | ||
const navigatorSpy = vi.spyOn(window.navigator, 'language', 'get'); | ||
navigatorSpy.mockReturnValue('en-US'); | ||
|
||
const intlSpy = vi.spyOn(Intl.DateTimeFormat.prototype, 'resolvedOptions'); | ||
intlSpy.mockReturnValue({ | ||
timeZone: 'UTC', | ||
locale: '', | ||
calendar: '', | ||
numberingSystem: '' | ||
}); | ||
|
||
const testDate = '2024-02-05T14:30:00Z' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate); | ||
expect(result).toBe('5 feb 2024, 15:30'); | ||
expect(result).toBe('Feb 5, 2024, 14:30'); | ||
}); | ||
|
||
it('pads minutes with leading zero when needed', () => { | ||
const testDate = '2024-02-05T14:05:00Z' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate); | ||
expect(result).toBe('5 feb 2024, 15:05'); | ||
it('formats date with custom locale and timezone', () => { | ||
const testDate = '2024-02-05T14:30:00Z' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate, { | ||
locale: 'it-IT', | ||
timeZone: 'UTC' | ||
}); | ||
expect(result).toBe('5 feb 2024, 14:30'); | ||
}); | ||
|
||
it('handles empty date input', () => { | ||
const testDate = '' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate); | ||
expect(result).toBe(' '); | ||
expect(formatOCPDate('' as ISO8601Timestamp)).toBe(' '); | ||
expect(formatOCPDate(undefined as unknown as ISO8601Timestamp)).toBe(' '); | ||
}); | ||
|
||
it('handles undefined date input', () => { | ||
const testDate = undefined as unknown as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate); | ||
expect(result).toBe(' '); | ||
it('formats dates across month boundaries', () => { | ||
const testDate = '2024-01-31T23:30:00Z' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate, { | ||
locale: 'en-US', | ||
timeZone: 'UTC' | ||
}); | ||
expect(result).toBe('Jan 31, 2024, 23:30'); | ||
}); | ||
|
||
it('formats date at the end of year', () => { | ||
const testDate = '2024-12-31T23:59:00Z' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate); | ||
expect(result).toBe('1 gen 2025, 0:59'); | ||
it('formats dates across year boundaries', () => { | ||
const testDate = '2024-12-31T23:30:00Z' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate, { | ||
locale: 'en-US', | ||
timeZone: 'UTC' | ||
}); | ||
expect(result).toBe('Dec 31, 2024, 23:30'); | ||
}); | ||
|
||
it('formats date at the beginning of year', () => { | ||
const testDate = '2024-01-01T00:01:00Z' as ISO8601Timestamp; | ||
const result = formatOCPDate(testDate); | ||
expect(result).toBe('1 gen 2024, 1:01'); | ||
it('formats dates consistently across different locales', () => { | ||
const testDate = '2024-02-05T14:30:00Z' as ISO8601Timestamp; | ||
const locales = ['en-US', 'it-IT', 'ja-JP', 'de-DE']; | ||
|
||
locales.forEach((locale) => { | ||
const result = formatOCPDate(testDate, { | ||
locale, | ||
timeZone: 'UTC' | ||
}); | ||
expect(result).toMatch(/[\d\s\w,:]+/); // Verifies format without specific string | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,32 @@ | ||
import { ISO8601Timestamp } from '@interfaces/CRD_Base'; | ||
|
||
export function formatOCPDate(date: ISO8601Timestamp): string { | ||
interface FormatOptions { | ||
locale?: string; | ||
timeZone?: string; | ||
} | ||
|
||
export function formatOCPDate(date: ISO8601Timestamp, options: FormatOptions = {}): string { | ||
if (!date) { | ||
return ' '; | ||
} | ||
|
||
const { locale = navigator.language, timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone } = options; | ||
|
||
const baseTime = new Date(date); | ||
|
||
// Format date as 'DD MMM YYYY' and time as 'HH:mm' | ||
const formattedDate = `${baseTime.getDate()} ${baseTime.toLocaleString('it-IT', { month: 'short' })} ${baseTime.getFullYear()}`; | ||
const formattedTime = `${baseTime.getHours()}:${baseTime.getMinutes().toString().padStart(2, '0')}`; | ||
const formattedDate = baseTime.toLocaleDateString(locale, { | ||
day: 'numeric', | ||
month: 'short', | ||
year: 'numeric', | ||
timeZone | ||
}); | ||
|
||
const formattedTime = baseTime.toLocaleTimeString(locale, { | ||
hour: 'numeric', | ||
minute: '2-digit', | ||
hour12: false, | ||
timeZone | ||
}); | ||
|
||
return `${formattedDate}, ${formattedTime}`; | ||
} |