Skip to content

Commit

Permalink
Split test file and move tests closer to the code
Browse files Browse the repository at this point in the history
Also:
- improve some tests
- update JSDoc
- trigger the Vitest GitHub action reporter when a test fails
- add code coverage to Vitest UI
- exclude types from code coverage
- lint tests with more rules
  • Loading branch information
meduzen authored Apr 8, 2024
1 parent 335472b commit 58420de
Show file tree
Hide file tree
Showing 18 changed files with 796 additions and 313 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ jobs:
- run: pnpm install --no-frozen-lockfile
- run: pnpm lint
- run: pnpm test
env:
GITHUB_ACTIONS: true
- run: pnpm test:types
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ Compare with [last published version](https://github.com/meduzen/datetime-attrib

### Under the hood

- Enforce type definitions for optional properties of the internal config functions `setConfig` and `setTzConfig`: it was possible to use them by omitting the `separator` property, it’s not anymore.
- Upgrade ESLint from 8 to [9](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/).
- Enforce type definitions for optional properties of the internal config functions `setConfig` and `setTzConfig`: it was possible to omit their `separator` property, it’s not anymore.
- Upgrade ESLint from 8 to [9](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/) and lint tests using [`eslint-plugin-vitest`](https://github.com/veritem/eslint-plugin-vitest).
- Split test file and move tests closer to the code.

## v1.3.3 (2024-02-23)

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,11 +411,11 @@ Calculate the difference between 2 dates in days, **discarding the time of day**
```js
import { daysBetween } from 'datetime-attribute'

const january1st = new Date(2021, 0, 1, 10, 10, 12)
const january1st2021 = new Date(2021, 0, 1, 10, 10, 12)
const january11th = new Date(2021, 0, 11, 10, 10, 12)
const january19th = new Date(2021, 0, 19, 10, 10, 12)

daysBetween(january1st, january11th) // 10
daysBetween(january1st2021, january11th) // 10
daysBetween(january19th, january11th) // -8
```

Expand All @@ -433,12 +433,12 @@ It accepts a `Date` object.
```js
import { weekNumber } from 'datetime-attribute'

const january1st = new Date(2021, 0, 1, 10, 10, 12)
const january1st2021 = new Date(2021, 0, 1, 10, 10, 12)
const january11th = new Date(2021, 0, 11, 10, 10, 12)
const togoIndependanceDay = new Date(1960, 3, 27)

weekNumber(togoIndependanceDay) // 17
weekNumber(january1st) // 53: it’s a Friday!
weekNumber(january1st2021) // 53: it’s a Friday!
weekNumber(january11th) // 2
```

Expand Down
8 changes: 6 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,13 @@ export default tseslint.config(
rules: {
...vitest.configs.recommended.rules,
// ...vitest.configs.all.rules, // worth testing from time to time…
// 'vitest/consistent-test-it': 0,

// Additional rules below taken from `vitest.configs.all.rules`
'vitest/consistent-test-it': 0,
'vitest/no-hooks': 0, // when testing `vitest.configs.all.rules`
'vitest/no-test-return-statement': 1,
// 'vitest/prefer-expect-assertions': 0, // when testing `vitest.configs.all.rules`
'vitest/prefer-expect-assertions': 0, // when testing `vitest.configs.all.rules`
'vitest/prefer-todo': 1,
'vitest/require-to-throw-message': 1,
},
languageOptions: {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"types": "tsc",
"test": "vitest run",
"test:types": "pnpm exec tsd",
"test:ui": "vitest --ui",
"coverage": "vitest run --coverage",
"test:ui": "vitest --ui --coverage.enabled --coverage.exclude=types",
"coverage": "vitest run --coverage --coverage.exclude=types",
"watch": "vitest watch",
"build": "echo \"Nothing to build, this command is only here to please size-limit GitHub action\" && exit 0",
"size": "size-limit",
Expand Down
63 changes: 63 additions & 0 deletions src/config/datetime.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { describe, expect, test } from 'vitest'

import { datetime, setTimeSeparator } from '../index.js'

import { setConfig } from './datetime.js'

const togoIndependanceDay = new Date(1960, 3, 27)
const date = togoIndependanceDay // alias for the sake of brevity

describe('setTimeSeparator', () => {

test('is a function', () => {
expect(setTimeSeparator).toBeInstanceOf(Function)
})

test('throws with invalid separator', () => {
expect(() => setTimeSeparator(42)).toThrow(Error)
})

test('no time separator', () => {
setTimeSeparator()
expect(datetime(date, 'datetime')).toBe('1960-04-27T00:00')
})

test('T as time separator', () => {
setTimeSeparator('T')
expect(datetime(date, 'datetime')).toBe('1960-04-27T00:00')
})

test('space as time separator', () => {
setTimeSeparator(' ')
expect(datetime(date, 'datetime')).toBe('1960-04-27 00:00')
})
})

describe('setConfig', () => {

test('is a function', () => {
expect(setConfig).toBeInstanceOf(Function)
})

test('throws without parameter', () => {
expect(() => setConfig()).toThrow(TypeError)
})

test('throws without proper parameter', () => {
expect(() => setConfig({})).toThrow(Error)
})

test('throws with invalid separator', () => {
expect(() => setConfig({ separator: 42 })).toThrow(Error)
})

test('T as time separator using datetime', () => {
setConfig({ separator: 'T' })
expect(datetime(date, 'datetime')).toBe('1960-04-27T00:00')
})

test('space as time separator using datetime', () => {
setConfig({ separator: ' ' })
expect(datetime(date, 'datetime')).toBe('1960-04-27 00:00')
})
})
55 changes: 55 additions & 0 deletions src/config/tz.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { describe, expect, test } from 'vitest'

import { datetimeTz, tzOffset, setTzSeparator } from '../index.js'

import { setTzConfig } from './tz.js'

const togoIndependanceDay = new Date(1960, 3, 27)
const date = togoIndependanceDay // alias for the sake of brevity

describe('setTzSeparator', () => {
test('is a function', () => expect(setTzSeparator).toBeInstanceOf(Function))
test('throws with invalid separator', () => expect(() => setTzSeparator(42)).toThrow(Error))

test('no timezone separator', () => {
setTzSeparator()
expect(tzOffset(3)).toBe('+0300')
})

test('empty string timezone separator', () => {
setTzSeparator('')
expect(tzOffset(3)).toBe('+0300')
})

test(': as timezone separator', () => {
setTzSeparator(':')
expect(tzOffset(3)).toBe('+03:00')
})

test('empty string timezone separator with datetimeTz', () => {
setTzSeparator('')
expect(datetimeTz(date, 'datetime second', -6)).toBe('1960-04-27T00:00:00-0600')
})
})

describe('setTzConfig', () => {
test('is a function', () => expect(setTzConfig).toBeInstanceOf(Function))
test('throws without parameter', () => expect(() => setTzConfig()).toThrow(TypeError))
test('throws without proper parameter', () => expect(() => setTzConfig({})).toThrow(Error))
test('throws with invalid separator', () => expect(() => setTzConfig({ separator: 42 })).toThrow(Error))

test('empty string timezone separator using tzOffset', () => {
setTzConfig({ separator: '' })
expect(tzOffset(3)).toBe('+0300')
})

test(': as timezone separator using tzOffset', () => {
setTzConfig({ separator: ':' })
expect(tzOffset(3)).toBe('+03:00')
})

test(': as timezone separator with datetimeTz', () => {
setTzConfig({ separator: ':' })
expect(datetimeTz(date, 'datetime second', -6)).toBe('1960-04-27T00:00:00-06:00')
})
})
7 changes: 7 additions & 0 deletions src/datetime-class.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ export class DateTime extends Date {
* - the first week of the year includes a Thursday;
* - week numbers go from 1 to 53 (https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#week-number-of-the-last-day).
*
* @todo: cache the result of weekNumber as long as date isn’t changed:
* compare the current object timestamp wuth a stored/cached one in
* order to decide if the cache is stale.
*
* @returns {number}
*/
getWeek = () => weekNumber(this)

/**
* Set the week number.
*
* If the week number is outside the year range, the `DateTime` object is
* updated accordingly.
*
* @param {number} weekNumber
* @returns {number} Milliseconds since midnight on January 1, 1970, UTC
*/
Expand Down
70 changes: 70 additions & 0 deletions src/datetime-class.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { beforeEach, describe, expect, test } from 'vitest'

import { DateTime, datetime } from './index.js'
import { MILLISECONDS_PER_DAY } from './utils/const.js'

const FOURTEEN_DAYS_IN_MS = MILLISECONDS_PER_DAY * 14

describe('DateTime class', () => {
/** @type {Date} */ let summer
/** @type {Date} */ let twoWeeksIntoSummer
/** @type {Date} */ let winter
/** @type {Date} */ let twoWeeksIntoWinter

beforeEach(() => {
summer = new DateTime(2021, 5, 21)
twoWeeksIntoSummer = new DateTime(summer.getTime() + FOURTEEN_DAYS_IN_MS) // same as `new DateTime(2021, 6, 5)`

winter = new DateTime(2021, 11, 21)
twoWeeksIntoWinter = new DateTime(winter.getTime() + FOURTEEN_DAYS_IN_MS) // same as `new DateTime(2022, 1, 4)`
})

test('extends the Date class', () => {
expect(summer).toBeInstanceOf(DateTime)
expect(summer).toBeInstanceOf(Date)
})

describe('.to() == datetime()', () => {

test('with default precision', () => {
expect(summer.to()).toBe('2021-06-21')
expect(datetime(summer)).toBe('2021-06-21')
})

test(`with 'month' precision`, () => {
expect(twoWeeksIntoSummer.to('month')).toBe('2021-07')
expect(datetime(twoWeeksIntoSummer, 'month')).toBe('2021-07')
})

test(`with 'week' precision, after the week is changed to a new year`, () => {
winter.setDate(winter.getDate() + 14)

expect(winter.to('week')).toBe(twoWeeksIntoWinter.to('week'))
expect(winter.to('week')).toBe('2022-W01')
expect(datetime(winter, 'week')).toBe('2022-W01')
})
})

describe('.getWeek()', () => {

test('returns the week number', () => {
expect(summer.getWeek()).toBe(25)
})

test('returns the week number after the date is changed', () => {
summer.setDate(summer.getDate() + 14)

expect(summer.getWeek()).toBe(twoWeeksIntoSummer.getWeek())
})

test('returns the week number after the date is changed to a new year', () => {
winter.setDate(winter.getDate() + 14)

expect(winter.getWeek()).toBe(twoWeeksIntoWinter.getWeek())
})
})

test('.setWeek() returns the timestamp of the changed date', () => {
expect(summer.setWeek(27)).toBe(twoWeeksIntoSummer.getTime())
})
})
Loading

0 comments on commit 58420de

Please sign in to comment.