@quatrain/core 1.2.13 → 1.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/core",
3
- "version": "1.2.13",
3
+ "version": "1.2.15",
4
4
  "description": "Core objects for business apps",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@quatrain/log": "^1.2.3",
36
- "@quatrain/types": "^1.2.12",
36
+ "@quatrain/types": "^1.2.13",
37
37
  "node-persist": "^4.0.4",
38
38
  "which": "^5.0.0"
39
39
  },
@@ -71,4 +71,43 @@ describe('Object Uri', () => {
71
71
  uri.collection = 'collection'
72
72
  expect(uri.collection).toBe('collection')
73
73
  })
74
+
75
+ test('exceptions and error boundaries', () => {
76
+ // 1. Odd number of path parts (> 1) and not a file
77
+ expect(() => new ObjectUri('part1/part2/part3')).toThrow("Path parts number must be 1 or even")
78
+
79
+ const uri = new ObjectUri('collection/uid')
80
+
81
+ // 2. class setter/getter
82
+ uri.class = { name: 'MyClass' }
83
+ expect(uri.collection).toBe('myclass')
84
+ expect(uri.class).toEqual({ name: 'MyClass' })
85
+
86
+ uri.class = null
87
+ expect(uri.collection).toBeUndefined()
88
+
89
+ // 3. ownPath getter
90
+ const parentUri = new ObjectUri('collection1/uid1/collection2/uid2')
91
+ expect(parentUri.ownPath).toBe('collection2/uid2')
92
+
93
+ // 4. collection setter exception
94
+ const lockedUri = new ObjectUri('collection/uid')
95
+ expect(() => { lockedUri.collection = 'new-collection' }).toThrow('Collection value already set')
96
+
97
+ // 5. toReference and toJSON
98
+ const refUri = new ObjectUri('@s3:collection/uid', 'my label')
99
+ refUri.path = 'collection/uid'
100
+ expect(refUri.toReference()).toEqual({
101
+ ref: 'collection/uid',
102
+ uri: '@s3:collection/uid',
103
+ label: 'my label'
104
+ })
105
+
106
+ expect(refUri.toJSON()).toEqual({
107
+ ref: 'collection/uid',
108
+ label: 'my label',
109
+ backend: '@s3'
110
+ })
111
+ })
74
112
  })
113
+
@@ -0,0 +1,91 @@
1
+ import { DateTimeProperty } from './DateTimeProperty'
2
+
3
+ describe('DateTimeProperty', () => {
4
+ afterEach(() => {
5
+ // Restore default global setting after each test
6
+ DateTimeProperty.RETURN_AS = DateTimeProperty.AS_IS
7
+ })
8
+
9
+ describe('timezone configuration', () => {
10
+ it('should default to "Z" timezone if none is provided', () => {
11
+ const prop = new DateTimeProperty({ name: 'testDate' })
12
+ expect(prop.timezone).toBe('Z')
13
+ })
14
+
15
+ it('should accept and return a custom timezone string', () => {
16
+ const prop = new DateTimeProperty({ name: 'testDate', timezone: 'Europe/Paris' })
17
+ expect(prop.timezone).toBe('Europe/Paris')
18
+ })
19
+ })
20
+
21
+ describe('value setting with default RETURN_AS = asis', () => {
22
+ it('should set and get values unmodified', () => {
23
+ const prop = new DateTimeProperty({ name: 'testDate' })
24
+ const date = new Date()
25
+
26
+ prop.set(date)
27
+ expect(prop.val()).toBe(date)
28
+
29
+ prop.set('2026-05-24T09:00:00Z')
30
+ expect(prop.val()).toBe('2026-05-24T09:00:00Z')
31
+
32
+ prop.set(1716537600000)
33
+ expect(prop.val()).toBe(1716537600000)
34
+ })
35
+ })
36
+
37
+ describe('value setting with RETURN_AS = unix_timestamp', () => {
38
+ beforeEach(() => {
39
+ DateTimeProperty.RETURN_AS = DateTimeProperty.UNIX_TIMESTAMP
40
+ })
41
+
42
+ it('should convert JS Date objects to UNIX timestamp milliseconds', () => {
43
+ const prop = new DateTimeProperty({ name: 'testDate' })
44
+ const date = new Date('2026-05-24T12:00:00.000Z')
45
+
46
+ prop.set(date)
47
+ expect(prop.val()).toBe(date.getTime())
48
+ })
49
+
50
+ it('should parse ISO strings with trailing Z as UTC timestamps', () => {
51
+ const prop = new DateTimeProperty({ name: 'testDate' })
52
+ prop.set('2026-05-24T12:00:00.000Z')
53
+
54
+ const expectedTime = Date.parse('2026-05-24T12:00:00.000Z')
55
+ expect(prop.val()).toBe(expectedTime)
56
+ })
57
+
58
+ it('should parse ISO strings with timezone offsets correctly', () => {
59
+ const prop = new DateTimeProperty({ name: 'testDate' })
60
+ prop.set('2026-05-24T12:00:00+02:00')
61
+
62
+ const expectedTime = Date.parse('2026-05-24T12:00:00+02:00')
63
+ expect(prop.val()).toBe(expectedTime)
64
+ })
65
+
66
+ it('should treat plain date strings without timezone as UTC by appending T and Z', () => {
67
+ const prop = new DateTimeProperty({ name: 'testDate' })
68
+
69
+ // Non-ISO string with space, no offset
70
+ prop.set('2026-05-24 12:00:00')
71
+
72
+ const expectedTime = Date.parse('2026-05-24T12:00:00Z')
73
+ expect(prop.val()).toBe(expectedTime)
74
+ })
75
+
76
+ it('should pass numeric timestamps directly', () => {
77
+ const prop = new DateTimeProperty({ name: 'testDate' })
78
+ const timestamp = 1716552000000
79
+
80
+ prop.set(timestamp)
81
+ expect(prop.val()).toBe(timestamp)
82
+ })
83
+
84
+ it('should handle falsy/empty values gracefully without throw', () => {
85
+ const prop = new DateTimeProperty({ name: 'testDate' })
86
+
87
+ prop.set('')
88
+ expect(prop.val()).toBe('')
89
+ })
90
+ })
91
+ })