LearnNewsExamplesServices
Frontmatter
id18995
titleAdd direct unit coverage for Neo.util.Date
stateClosed
labels
enhancementgood first issueaitestingcore
assigneessandeep780049
createdAtSep 19, 2026, 8:54 PM
updatedAtSep 19, 2026, 10:51 PM
githubUrlhttps://github.com/neomjs/neo/issues/18995
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 19, 2026, 10:51 PM

Add direct unit coverage for Neo.util.Date

Closed v13.2.0/archive-v13-2-0-chunk-22 enhancementgood first issueaitestingcore
neo-opus-ada
neo-opus-ada commented on Sep 19, 2026, 8:54 PM

New here? This issue is written to be finishable on a clean clone. You need Node, a fork and an evening. No Docker, no API key, no AI service, nothing beyond npm install. If anything below turns out to need more than that, say so in a comment — that is a bug in the issue, not in you.

Context

Every date surface in Neo computes its grid through one shared helper, Neo.util.Date: the calendar month, week and year views, Neo.form.field.Date, Neo.date.DayViewComponent, the calendar's event store and its drag plugins.

Measured on 2026-09-19 at dev@afddc57634: no file under test/playwright/ references src/util/Date.mjs — not by import, not by method name — while more than ten modules under src/ import it. Its eight static methods are exercised today only as a side effect of rendering a calendar.

The Problem

Week arithmetic is where off-by-one bugs live: leap years, a month that begins on a Sunday, a weekStartDay other than Monday, and the ISO rule that puts the first days of January in the last week of the previous year. Because nothing asserts these methods directly, such a bug first appears as a wrong calendar, and whoever fixes it has to reconstruct the failing case from a rendered component before they can even see it.

Direct coverage turns that into a one-line failure with the inputs printed.

The Architectural Reality

src/util/Date.mjs — class Neo.util.Date (the local binding is DateUtil), extends Neo.core.Base. Eight static methods, all pure, none touching the DOM or a worker:

method line contract
clone(date) :42 new Date with the same value; null in → null out
convertToyyyymmdd(date) :51 yyyy-mm-dd, shifted by the local timezone offset first
getDaysInMonth(date) :60 days in that date's month
getFirstDayOffset(date, weekStartDay) :69 0–6, how far the 1st sits from weekStartDay
getFirstDayOfMonth(date) :81 weekday of the 1st, 0–6 (Sun–Sat)
getWeekOfYear(targetDate) :91 ISO 8601 week number, computed in UTC
getWeeksOfMonth(date, weekStartDay) :112 documented as 5 or 6
matchDate(date1, date2) :125 same day, month and year

The Fix

Add one new spec: test/playwright/unit/util/Date.spec.mjs.

Copy the shape from its sibling test/playwright/unit/util/String.spec.mjs — the first eleven lines matter and are not optional:

import {setup} from '../../setup.mjs';

setup({
    appConfig: {
        name: 'DateUtilTest'
    }
});

import {test, expect} from '@playwright/test';
import Neo            from '../../../../src/Neo.mjs';
import * as core      from '../../../../src/core/_export.mjs';
import DateUtil       from '../../../../src/util/Date.mjs';

test.describe('Neo.util.Date', () => {
    // your tests
});

setup() must be called before the other imports; that is how the Neo class system is initialised for the unit tier.

Cases worth asserting — pick the ones you can state confidently; you do not have to cover all eight methods to have a useful PR:

  • clone() returns a different object with an equal value, and passes null through.
  • getDaysInMonth() across February 2024 (29) and February 2023 (28).
  • getFirstDayOfMonth() and getFirstDayOffset() for a month starting on a Sunday, with weekStartDay: 0 and with weekStartDay: 1 — the offset is documented as 0–6 and the wrap is the interesting half.
  • getWeekOfYear() on the ISO boundary: 2021-01-01 (a Friday) and 2019-12-30 (a Monday) are the classic pair where the calendar year and the ISO week year disagree.
  • matchDate() for two Date objects on the same day at different times.
  • getWeeksOfMonth() is documented as returning 5 or 6. February of a non-leap year that begins exactly on weekStartDay is 28 days in exactly four rows. Assert what the function actually returns for that input and say so in your PR — if it is not 4, that is worth knowing, and it is a finding rather than something for you to fix here.

Deterministic inputs only: construct explicit new Date(2024, 1, 1) values. No new Date(), no "today" — a test that depends on the day it runs will fail for someone else.

How to run it

npm install
npx playwright test -c test/playwright/playwright.config.unit.mjs test/playwright/unit/util/Date.spec.mjs

The whole unit tier is npm run test-unit. Do not run a bare npx playwright test — this repository has several Playwright configurations and the default one is not the unit tier.

Acceptance Criteria

  • test/playwright/unit/util/Date.spec.mjs exists and follows the setup()-first shape of its sibling specs.
  • At least four of the eight methods are asserted, each with inputs written out literally — no dependency on the current date, the machine's locale, or test execution order.
  • The spec passes on the unit configuration, and the PR body says how you ran it.
  • The getWeeksOfMonth four-row case is either asserted or reported in the PR body with the value it returned.
  • No file outside test/playwright/unit/util/ is changed. If a test of yours goes red against src/util/Date.mjs, do not fix the source here — say so in the PR and we will open a separate issue for the fix, with your test as its evidence.

Out of Scope

  • Changing anything in src/util/Date.mjs. This issue adds coverage to the code as it stands.
  • The calendar components that consume these methods; they have their own specs.
  • Locale-dependent name formatting (dayNameFormats, monthNameFormats): those static configs are validated by their consumers, and asserting them here would pull the test into locale territory this issue does not need.

Before you open the PR

  • Branch from dev and target dev — not main.
  • Run npm install at least once after cloning: it registers a Husky pre-commit hook that checks mechanical hygiene such as trailing whitespace. Committing without it will fail CI on something unrelated to your test.
  • https://github.com/neomjs/neo/blob/dev/CONTRIBUTING.md has the rest.

Related

#18985 — the Hacktoberfest 2026 contributor door this issue was curated for.

⚖️ Ada · @neo-opus-ada · Claude Opus 5 · Claude Code

sandeep780049 cross-referenced by PR #19004 on Sep 19, 2026, 10:32 PM
sandeep780049
sandeep780049 Sep 19, 2026, 10:32 PM

Taking this one — opening a PR shortly with a spec covering all eight methods (including the getWeeksOfMonth four-row February 2027 case the issue asked to report). PR: #19004

  • 2026-09-19T21:26:37Z @neo-opus-ada cross-referenced by #106
  • 2026-09-19T22:34:05Z @neo-gpt cross-referenced by PR #19012