prjct-cli 1.22.0 → 1.24.0
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/CHANGELOG.md +230 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct-core.mjs +1748 -0
- package/dist/bin/prjct.mjs +17 -36672
- package/dist/cli/linear.mjs +14 -0
- package/dist/daemon/entry.mjs +1429 -0
- package/dist/templates.json +1 -0
- package/package.json +4 -5
- package/bin/prjct.ts +0 -342
- package/core/__tests__/agentic/analysis-injection.test.ts +0 -377
- package/core/__tests__/agentic/cache-eviction.test.ts +0 -294
- package/core/__tests__/agentic/command-context.test.ts +0 -281
- package/core/__tests__/agentic/command-executor.test.ts +0 -659
- package/core/__tests__/agentic/domain-classifier.test.ts +0 -330
- package/core/__tests__/agentic/injection-validator.test.ts +0 -255
- package/core/__tests__/agentic/memory-system.test.ts +0 -281
- package/core/__tests__/agentic/plan-mode.test.ts +0 -386
- package/core/__tests__/agentic/prompt-assembly.test.ts +0 -298
- package/core/__tests__/agentic/prompt-builder.test.ts +0 -243
- package/core/__tests__/agentic/response-validator.test.ts +0 -263
- package/core/__tests__/agentic/semantic-matching.test.ts +0 -131
- package/core/__tests__/agentic/smart-context.test.ts +0 -372
- package/core/__tests__/agentic/tech-normalizer.test.ts +0 -136
- package/core/__tests__/agentic/token-budget.test.ts +0 -294
- package/core/__tests__/ai-tools/formatters.test.ts +0 -476
- package/core/__tests__/domain/bm25.test.ts +0 -225
- package/core/__tests__/domain/change-propagator.test.ts +0 -100
- package/core/__tests__/domain/fibonacci.test.ts +0 -113
- package/core/__tests__/domain/file-hasher.test.ts +0 -146
- package/core/__tests__/domain/file-ranker.test.ts +0 -169
- package/core/__tests__/domain/git-cochange.test.ts +0 -121
- package/core/__tests__/domain/import-graph.test.ts +0 -156
- package/core/__tests__/domain/velocity.test.ts +0 -623
- package/core/__tests__/infrastructure/performance-tracker.test.ts +0 -328
- package/core/__tests__/schemas/model.test.ts +0 -272
- package/core/__tests__/services/dependency-validator.test.ts +0 -175
- package/core/__tests__/services/hierarchical-agent-resolver.test.ts +0 -359
- package/core/__tests__/services/nested-context-resolver.test.ts +0 -443
- package/core/__tests__/services/project-index.test.ts +0 -355
- package/core/__tests__/services/staleness-checker.test.ts +0 -204
- package/core/__tests__/storage/analysis-storage.test.ts +0 -641
- package/core/__tests__/storage/archive-storage.test.ts +0 -455
- package/core/__tests__/storage/safe-reader.test.ts +0 -262
- package/core/__tests__/storage/sqlite-migration.test.ts +0 -1016
- package/core/__tests__/storage/state-storage-feedback.test.ts +0 -463
- package/core/__tests__/storage/state-storage-history.test.ts +0 -469
- package/core/__tests__/storage/storage-manager.test.ts +0 -383
- package/core/__tests__/storage/subtask-handoff.test.ts +0 -237
- package/core/__tests__/types/fs.test.ts +0 -125
- package/core/__tests__/utils/date-helper.test.ts +0 -449
- package/core/__tests__/utils/output.test.ts +0 -278
- package/core/__tests__/utils/preserve-sections.test.ts +0 -216
- package/core/__tests__/utils/project-commands.test.ts +0 -71
- package/core/__tests__/utils/retry.test.ts +0 -381
- package/core/__tests__/workflow/state-machine.test.ts +0 -216
- package/core/agentic/agent-router.ts +0 -150
- package/core/agentic/anti-hallucination.ts +0 -141
- package/core/agentic/chain-of-thought.ts +0 -234
- package/core/agentic/command-classifier.ts +0 -141
- package/core/agentic/command-context.ts +0 -168
- package/core/agentic/command-executor.ts +0 -471
- package/core/agentic/context-builder.ts +0 -285
- package/core/agentic/domain-classifier.ts +0 -525
- package/core/agentic/environment-block.ts +0 -102
- package/core/agentic/ground-truth.ts +0 -706
- package/core/agentic/index.ts +0 -193
- package/core/agentic/injection-validator.ts +0 -208
- package/core/agentic/loop-detector.ts +0 -451
- package/core/agentic/memory-system.ts +0 -1547
- package/core/agentic/orchestrator-executor.ts +0 -579
- package/core/agentic/plan-mode.ts +0 -525
- package/core/agentic/prompt-builder.ts +0 -1069
- package/core/agentic/response-validator.ts +0 -98
- package/core/agentic/services.ts +0 -167
- package/core/agentic/skill-loader.ts +0 -106
- package/core/agentic/smart-context.ts +0 -393
- package/core/agentic/tech-normalizer.ts +0 -167
- package/core/agentic/template-executor.ts +0 -272
- package/core/agentic/template-loader.ts +0 -109
- package/core/agentic/token-budget.ts +0 -226
- package/core/agentic/tool-registry.ts +0 -146
- package/core/agents/index.ts +0 -28
- package/core/agents/performance.ts +0 -429
- package/core/ai-tools/formatters.ts +0 -341
- package/core/ai-tools/generator.ts +0 -144
- package/core/ai-tools/index.ts +0 -15
- package/core/ai-tools/registry.ts +0 -201
- package/core/bus/bus.ts +0 -314
- package/core/bus/index.ts +0 -8
- package/core/cli/linear.ts +0 -500
- package/core/cli/lint-meta-commentary.ts +0 -177
- package/core/cli/start.ts +0 -386
- package/core/commands/analysis.ts +0 -1274
- package/core/commands/analytics.ts +0 -342
- package/core/commands/base.ts +0 -118
- package/core/commands/cleanup.ts +0 -157
- package/core/commands/command-data.ts +0 -463
- package/core/commands/commands.ts +0 -306
- package/core/commands/context.ts +0 -238
- package/core/commands/design.ts +0 -77
- package/core/commands/index.ts +0 -19
- package/core/commands/maintenance.ts +0 -77
- package/core/commands/performance.ts +0 -114
- package/core/commands/planning.ts +0 -662
- package/core/commands/register.ts +0 -127
- package/core/commands/registry.ts +0 -444
- package/core/commands/setup.ts +0 -280
- package/core/commands/shipping.ts +0 -267
- package/core/commands/snapshots.ts +0 -297
- package/core/commands/uninstall.ts +0 -542
- package/core/commands/velocity.ts +0 -149
- package/core/commands/workflow.ts +0 -505
- package/core/config/command-context.config.json +0 -66
- package/core/constants/index.ts +0 -379
- package/core/context/generator.ts +0 -368
- package/core/context-tools/files-tool.ts +0 -577
- package/core/context-tools/imports-tool.ts +0 -400
- package/core/context-tools/index.ts +0 -434
- package/core/context-tools/recent-tool.ts +0 -301
- package/core/context-tools/signatures-tool.ts +0 -495
- package/core/context-tools/summary-tool.ts +0 -301
- package/core/context-tools/token-counter.ts +0 -273
- package/core/context-tools/types.ts +0 -253
- package/core/domain/agent-generator.ts +0 -186
- package/core/domain/agent-loader.ts +0 -419
- package/core/domain/analyzer.ts +0 -387
- package/core/domain/architecture-generator.ts +0 -108
- package/core/domain/bm25.ts +0 -525
- package/core/domain/change-propagator.ts +0 -162
- package/core/domain/context-estimator.ts +0 -175
- package/core/domain/fibonacci.ts +0 -128
- package/core/domain/file-hasher.ts +0 -296
- package/core/domain/file-ranker.ts +0 -151
- package/core/domain/git-cochange.ts +0 -250
- package/core/domain/import-graph.ts +0 -315
- package/core/domain/snapshot-manager.ts +0 -415
- package/core/domain/task-stack.ts +0 -578
- package/core/domain/velocity.ts +0 -470
- package/core/errors.ts +0 -335
- package/core/events/events.ts +0 -85
- package/core/events/index.ts +0 -8
- package/core/index.ts +0 -481
- package/core/infrastructure/agent-detector.ts +0 -135
- package/core/infrastructure/ai-provider.ts +0 -578
- package/core/infrastructure/author-detector.ts +0 -133
- package/core/infrastructure/capability-installer.ts +0 -76
- package/core/infrastructure/claude-agent.ts +0 -297
- package/core/infrastructure/command-installer.ts +0 -752
- package/core/infrastructure/config-manager.ts +0 -364
- package/core/infrastructure/editors-config.ts +0 -172
- package/core/infrastructure/path-manager.ts +0 -571
- package/core/infrastructure/performance-tracker.ts +0 -326
- package/core/infrastructure/permission-manager.ts +0 -289
- package/core/infrastructure/setup.ts +0 -1061
- package/core/infrastructure/update-checker.ts +0 -246
- package/core/integrations/issue-tracker/enricher.ts +0 -271
- package/core/integrations/issue-tracker/index.ts +0 -8
- package/core/integrations/issue-tracker/manager.ts +0 -286
- package/core/integrations/issue-tracker/types.ts +0 -310
- package/core/integrations/jira/cache.ts +0 -57
- package/core/integrations/jira/client.ts +0 -688
- package/core/integrations/jira/index.ts +0 -23
- package/core/integrations/jira/service.ts +0 -244
- package/core/integrations/linear/cache.ts +0 -68
- package/core/integrations/linear/client.ts +0 -436
- package/core/integrations/linear/index.ts +0 -20
- package/core/integrations/linear/service.ts +0 -260
- package/core/integrations/linear/sync.ts +0 -314
- package/core/outcomes/analyzer.ts +0 -286
- package/core/outcomes/index.ts +0 -34
- package/core/outcomes/recorder.ts +0 -195
- package/core/plugin/builtin/webhook.ts +0 -148
- package/core/plugin/hooks.ts +0 -315
- package/core/plugin/index.ts +0 -50
- package/core/plugin/loader.ts +0 -354
- package/core/plugin/registry.ts +0 -326
- package/core/schemas/agents.ts +0 -27
- package/core/schemas/analysis.ts +0 -530
- package/core/schemas/classification.ts +0 -91
- package/core/schemas/command-context.ts +0 -29
- package/core/schemas/enriched-task.ts +0 -291
- package/core/schemas/ideas.ts +0 -114
- package/core/schemas/index.ts +0 -53
- package/core/schemas/issues.ts +0 -159
- package/core/schemas/llm-output.ts +0 -170
- package/core/schemas/metrics.ts +0 -143
- package/core/schemas/model.ts +0 -153
- package/core/schemas/outcomes.ts +0 -487
- package/core/schemas/performance.ts +0 -128
- package/core/schemas/permissions.ts +0 -180
- package/core/schemas/prd.ts +0 -450
- package/core/schemas/project.ts +0 -57
- package/core/schemas/roadmap.ts +0 -322
- package/core/schemas/schemas.ts +0 -38
- package/core/schemas/shipped.ts +0 -109
- package/core/schemas/state.ts +0 -284
- package/core/schemas/velocity.ts +0 -103
- package/core/server/index.ts +0 -21
- package/core/server/routes-extended.ts +0 -566
- package/core/server/routes.ts +0 -176
- package/core/server/server.ts +0 -149
- package/core/server/sse.ts +0 -192
- package/core/services/agent-generator.ts +0 -385
- package/core/services/agent-service.ts +0 -168
- package/core/services/breakdown-service.ts +0 -124
- package/core/services/context-generator.ts +0 -445
- package/core/services/context-selector.ts +0 -429
- package/core/services/dependency-validator.ts +0 -318
- package/core/services/diff-generator.ts +0 -313
- package/core/services/doctor-service.ts +0 -423
- package/core/services/file-categorizer.ts +0 -448
- package/core/services/file-scorer.ts +0 -270
- package/core/services/git-analyzer.ts +0 -293
- package/core/services/hierarchical-agent-resolver.ts +0 -236
- package/core/services/hooks-service.ts +0 -685
- package/core/services/index.ts +0 -46
- package/core/services/local-state-generator.ts +0 -158
- package/core/services/memory-service.ts +0 -181
- package/core/services/nested-context-resolver.ts +0 -842
- package/core/services/project-index.ts +0 -911
- package/core/services/project-service.ts +0 -155
- package/core/services/session-tracker.ts +0 -287
- package/core/services/skill-installer.ts +0 -447
- package/core/services/skill-lock.ts +0 -132
- package/core/services/skill-service.ts +0 -306
- package/core/services/stack-detector.ts +0 -229
- package/core/services/staleness-checker.ts +0 -327
- package/core/services/sync-service.ts +0 -1515
- package/core/services/sync-verifier.ts +0 -253
- package/core/services/watch-service.ts +0 -312
- package/core/session/compaction.ts +0 -248
- package/core/session/index.ts +0 -35
- package/core/session/log-migration.ts +0 -88
- package/core/session/metrics.ts +0 -323
- package/core/session/session-log-manager.ts +0 -307
- package/core/session/task-session-manager.ts +0 -404
- package/core/session/utils.ts +0 -51
- package/core/storage/analysis-storage.ts +0 -373
- package/core/storage/archive-storage.ts +0 -205
- package/core/storage/database.ts +0 -575
- package/core/storage/ideas-storage.ts +0 -298
- package/core/storage/index-storage.ts +0 -523
- package/core/storage/index.ts +0 -79
- package/core/storage/metrics-storage.ts +0 -321
- package/core/storage/migrate-json.ts +0 -720
- package/core/storage/queue-storage.ts +0 -336
- package/core/storage/safe-reader.ts +0 -105
- package/core/storage/shipped-storage.ts +0 -253
- package/core/storage/state-storage.ts +0 -1035
- package/core/storage/storage-manager.ts +0 -205
- package/core/storage/storage.ts +0 -177
- package/core/storage/velocity-storage.ts +0 -149
- package/core/sync/auth-config.ts +0 -138
- package/core/sync/index.ts +0 -31
- package/core/sync/oauth-handler.ts +0 -143
- package/core/sync/sync-client.ts +0 -251
- package/core/sync/sync-manager.ts +0 -327
- package/core/tsconfig.json +0 -22
- package/core/types/agentic.ts +0 -760
- package/core/types/agents.ts +0 -150
- package/core/types/bus.ts +0 -193
- package/core/types/citations.ts +0 -22
- package/core/types/commands.ts +0 -399
- package/core/types/config.ts +0 -92
- package/core/types/core.ts +0 -96
- package/core/types/diff.ts +0 -41
- package/core/types/domain.ts +0 -71
- package/core/types/errors.ts +0 -111
- package/core/types/events.ts +0 -42
- package/core/types/fs.ts +0 -72
- package/core/types/index.ts +0 -510
- package/core/types/infrastructure.ts +0 -210
- package/core/types/integrations.ts +0 -31
- package/core/types/jira.ts +0 -51
- package/core/types/logger.ts +0 -17
- package/core/types/memory.ts +0 -313
- package/core/types/outcomes.ts +0 -190
- package/core/types/output.ts +0 -47
- package/core/types/plugin.ts +0 -25
- package/core/types/project-sync.ts +0 -129
- package/core/types/provider.ts +0 -163
- package/core/types/server.ts +0 -71
- package/core/types/services.ts +0 -84
- package/core/types/session.ts +0 -135
- package/core/types/stack.ts +0 -19
- package/core/types/storage.ts +0 -318
- package/core/types/sync-verifier.ts +0 -33
- package/core/types/sync.ts +0 -121
- package/core/types/task.ts +0 -72
- package/core/types/template.ts +0 -24
- package/core/types/utils.ts +0 -92
- package/core/types/workflow.ts +0 -23
- package/core/utils/agent-stream.ts +0 -140
- package/core/utils/animations.ts +0 -251
- package/core/utils/branding.ts +0 -88
- package/core/utils/cache.ts +0 -187
- package/core/utils/citations.ts +0 -39
- package/core/utils/collection-filters.ts +0 -209
- package/core/utils/date-helper.ts +0 -176
- package/core/utils/error-messages.ts +0 -38
- package/core/utils/file-helper.ts +0 -277
- package/core/utils/fs-helpers.ts +0 -14
- package/core/utils/help.ts +0 -314
- package/core/utils/jsonl-helper.ts +0 -290
- package/core/utils/keychain.ts +0 -127
- package/core/utils/logger.ts +0 -77
- package/core/utils/markdown-builder.ts +0 -280
- package/core/utils/next-steps.ts +0 -95
- package/core/utils/output.ts +0 -403
- package/core/utils/preserve-sections.ts +0 -218
- package/core/utils/project-commands.ts +0 -126
- package/core/utils/project-credentials.ts +0 -143
- package/core/utils/provider-cache.ts +0 -49
- package/core/utils/retry.ts +0 -318
- package/core/utils/runtime.ts +0 -108
- package/core/utils/session-helper.ts +0 -278
- package/core/utils/subtask-table.ts +0 -227
- package/core/utils/version.ts +0 -128
- package/core/wizard/index.ts +0 -13
- package/core/wizard/onboarding.ts +0 -633
- package/core/workflow/index.ts +0 -7
- package/core/workflow/state-machine.ts +0 -198
- package/core/workflow/workflow-preferences.ts +0 -294
- package/dist/core/infrastructure/command-installer.js +0 -1141
- package/dist/core/infrastructure/editors-config.js +0 -177
- package/dist/core/infrastructure/setup.js +0 -2244
- package/dist/core/utils/version.js +0 -141
- package/templates/agentic/agent-routing.md +0 -45
- package/templates/agentic/agents/uxui.md +0 -63
- package/templates/agentic/checklist-routing.md +0 -98
- package/templates/agentic/orchestrator.md +0 -68
- package/templates/agentic/task-fragmentation.md +0 -89
- package/templates/agents/AGENTS.md +0 -68
- package/templates/analysis/analyze.md +0 -84
- package/templates/analysis/patterns.md +0 -60
- package/templates/antigravity/SKILL.md +0 -39
- package/templates/architect/discovery.md +0 -67
- package/templates/architect/phases.md +0 -59
- package/templates/checklists/architecture.md +0 -28
- package/templates/checklists/code-quality.md +0 -28
- package/templates/checklists/data.md +0 -33
- package/templates/checklists/documentation.md +0 -33
- package/templates/checklists/infrastructure.md +0 -33
- package/templates/checklists/performance.md +0 -33
- package/templates/checklists/security.md +0 -33
- package/templates/checklists/testing.md +0 -33
- package/templates/checklists/ux-ui.md +0 -37
- package/templates/commands/analyze.md +0 -56
- package/templates/commands/auth.md +0 -234
- package/templates/commands/bug.md +0 -163
- package/templates/commands/cleanup.md +0 -19
- package/templates/commands/dash.md +0 -99
- package/templates/commands/design.md +0 -15
- package/templates/commands/done.md +0 -291
- package/templates/commands/enrich.md +0 -174
- package/templates/commands/git.md +0 -295
- package/templates/commands/history.md +0 -389
- package/templates/commands/idea.md +0 -88
- package/templates/commands/impact.md +0 -864
- package/templates/commands/init.md +0 -54
- package/templates/commands/jira.md +0 -278
- package/templates/commands/linear.md +0 -288
- package/templates/commands/merge.md +0 -206
- package/templates/commands/next.md +0 -80
- package/templates/commands/p.md +0 -67
- package/templates/commands/p.toml +0 -37
- package/templates/commands/pause.md +0 -136
- package/templates/commands/plan.md +0 -696
- package/templates/commands/prd.md +0 -356
- package/templates/commands/resume.md +0 -171
- package/templates/commands/review.md +0 -276
- package/templates/commands/serve.md +0 -118
- package/templates/commands/setup.md +0 -91
- package/templates/commands/ship.md +0 -475
- package/templates/commands/skill.md +0 -259
- package/templates/commands/spec.md +0 -218
- package/templates/commands/status.md +0 -207
- package/templates/commands/sync.md +0 -104
- package/templates/commands/task.md +0 -312
- package/templates/commands/test.md +0 -93
- package/templates/commands/update.md +0 -63
- package/templates/commands/verify.md +0 -204
- package/templates/commands/workflow.md +0 -150
- package/templates/config/skill-mappings.json +0 -82
- package/templates/context/dashboard.md +0 -256
- package/templates/context/roadmap.md +0 -221
- package/templates/cursor/commands/bug.md +0 -8
- package/templates/cursor/commands/done.md +0 -4
- package/templates/cursor/commands/pause.md +0 -6
- package/templates/cursor/commands/resume.md +0 -4
- package/templates/cursor/commands/ship.md +0 -8
- package/templates/cursor/commands/sync.md +0 -4
- package/templates/cursor/commands/task.md +0 -8
- package/templates/cursor/p.md +0 -29
- package/templates/cursor/router.mdc +0 -28
- package/templates/design/api.md +0 -95
- package/templates/design/architecture.md +0 -77
- package/templates/design/component.md +0 -89
- package/templates/design/database.md +0 -78
- package/templates/design/flow.md +0 -94
- package/templates/global/ANTIGRAVITY.md +0 -254
- package/templates/global/CLAUDE.md +0 -497
- package/templates/global/CURSOR.mdc +0 -266
- package/templates/global/GEMINI.md +0 -293
- package/templates/global/STORAGE-SPEC.md +0 -391
- package/templates/global/WINDSURF.md +0 -266
- package/templates/global/modules/CLAUDE-commands.md +0 -70
- package/templates/global/modules/CLAUDE-core.md +0 -105
- package/templates/global/modules/CLAUDE-git.md +0 -50
- package/templates/global/modules/CLAUDE-intelligence.md +0 -92
- package/templates/global/modules/CLAUDE-storage.md +0 -50
- package/templates/global/modules/module-config.json +0 -36
- package/templates/mcp-config.json +0 -19
- package/templates/permissions/default.jsonc +0 -60
- package/templates/permissions/permissive.jsonc +0 -49
- package/templates/permissions/strict.jsonc +0 -58
- package/templates/planning-methodology.md +0 -195
- package/templates/skills/code-review.md +0 -47
- package/templates/skills/debug.md +0 -61
- package/templates/skills/refactor.md +0 -47
- package/templates/subagents/agent-base.md +0 -20
- package/templates/subagents/domain/backend.md +0 -109
- package/templates/subagents/domain/database.md +0 -121
- package/templates/subagents/domain/devops.md +0 -152
- package/templates/subagents/domain/frontend.md +0 -103
- package/templates/subagents/domain/testing.md +0 -169
- package/templates/subagents/pm-expert.md +0 -366
- package/templates/subagents/workflow/chief-architect.md +0 -657
- package/templates/subagents/workflow/prjct-planner.md +0 -159
- package/templates/subagents/workflow/prjct-shipper.md +0 -188
- package/templates/subagents/workflow/prjct-workflow.md +0 -98
- package/templates/tools/bash.txt +0 -22
- package/templates/tools/edit.txt +0 -18
- package/templates/tools/glob.txt +0 -19
- package/templates/tools/grep.txt +0 -21
- package/templates/tools/read.txt +0 -14
- package/templates/tools/task.txt +0 -20
- package/templates/tools/webfetch.txt +0 -16
- package/templates/tools/websearch.txt +0 -18
- package/templates/tools/write.txt +0 -17
- package/templates/windsurf/router.md +0 -28
- package/templates/windsurf/workflows/bug.md +0 -8
- package/templates/windsurf/workflows/done.md +0 -4
- package/templates/windsurf/workflows/pause.md +0 -4
- package/templates/windsurf/workflows/resume.md +0 -4
- package/templates/windsurf/workflows/ship.md +0 -8
- package/templates/windsurf/workflows/sync.md +0 -4
- package/templates/windsurf/workflows/task.md +0 -8
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FS Types Tests
|
|
3
|
-
* Tests for file system error utilities
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, expect, it } from 'bun:test'
|
|
7
|
-
import {
|
|
8
|
-
isDirNotEmptyError,
|
|
9
|
-
isFileExistsError,
|
|
10
|
-
isNodeError,
|
|
11
|
-
isNotFoundError,
|
|
12
|
-
isPermissionError,
|
|
13
|
-
} from '../../types/fs'
|
|
14
|
-
|
|
15
|
-
describe('FS Error Utilities', () => {
|
|
16
|
-
describe('isNotFoundError', () => {
|
|
17
|
-
it('should return true for ENOENT error', () => {
|
|
18
|
-
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
19
|
-
error.code = 'ENOENT'
|
|
20
|
-
expect(isNotFoundError(error)).toBe(true)
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('should return false for other error codes', () => {
|
|
24
|
-
const error = new Error('Permission denied') as NodeJS.ErrnoException
|
|
25
|
-
error.code = 'EACCES'
|
|
26
|
-
expect(isNotFoundError(error)).toBe(false)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('should return false for errors without code', () => {
|
|
30
|
-
const error = new Error('Generic error')
|
|
31
|
-
expect(isNotFoundError(error)).toBe(false)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('should return false for non-error values', () => {
|
|
35
|
-
expect(isNotFoundError(null)).toBe(false)
|
|
36
|
-
expect(isNotFoundError(undefined)).toBe(false)
|
|
37
|
-
expect(isNotFoundError('string')).toBe(false)
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
describe('isPermissionError', () => {
|
|
42
|
-
it('should return true for EACCES error', () => {
|
|
43
|
-
const error = new Error('Permission denied') as NodeJS.ErrnoException
|
|
44
|
-
error.code = 'EACCES'
|
|
45
|
-
expect(isPermissionError(error)).toBe(true)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('should return true for EPERM error', () => {
|
|
49
|
-
const error = new Error('Operation not permitted') as NodeJS.ErrnoException
|
|
50
|
-
error.code = 'EPERM'
|
|
51
|
-
expect(isPermissionError(error)).toBe(true)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should return false for other error codes', () => {
|
|
55
|
-
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
56
|
-
error.code = 'ENOENT'
|
|
57
|
-
expect(isPermissionError(error)).toBe(false)
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
describe('isDirNotEmptyError', () => {
|
|
62
|
-
it('should return true for ENOTEMPTY error', () => {
|
|
63
|
-
const error = new Error('Directory not empty') as NodeJS.ErrnoException
|
|
64
|
-
error.code = 'ENOTEMPTY'
|
|
65
|
-
expect(isDirNotEmptyError(error)).toBe(true)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('should return false for other error codes', () => {
|
|
69
|
-
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
70
|
-
error.code = 'ENOENT'
|
|
71
|
-
expect(isDirNotEmptyError(error)).toBe(false)
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
describe('isFileExistsError', () => {
|
|
76
|
-
it('should return true for EEXIST error', () => {
|
|
77
|
-
const error = new Error('File exists') as NodeJS.ErrnoException
|
|
78
|
-
error.code = 'EEXIST'
|
|
79
|
-
expect(isFileExistsError(error)).toBe(true)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('should return false for other error codes', () => {
|
|
83
|
-
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
84
|
-
error.code = 'ENOENT'
|
|
85
|
-
expect(isFileExistsError(error)).toBe(false)
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
describe('isNodeError', () => {
|
|
90
|
-
it('should return true for Error with code property', () => {
|
|
91
|
-
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
92
|
-
error.code = 'ENOENT'
|
|
93
|
-
expect(isNodeError(error)).toBe(true)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('should return false for Error without code property', () => {
|
|
97
|
-
const error = new Error('Generic error')
|
|
98
|
-
expect(isNodeError(error)).toBe(false)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should return false for non-Error values', () => {
|
|
102
|
-
expect(isNodeError(null)).toBe(false)
|
|
103
|
-
expect(isNodeError({ code: 'ENOENT' })).toBe(false) // Not an Error instance
|
|
104
|
-
})
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
describe('SyntaxError handling pattern', () => {
|
|
108
|
-
it('should differentiate SyntaxError from fs errors', () => {
|
|
109
|
-
const syntaxError = new SyntaxError('Unexpected token')
|
|
110
|
-
const fsError = new Error('File not found') as NodeJS.ErrnoException
|
|
111
|
-
fsError.code = 'ENOENT'
|
|
112
|
-
|
|
113
|
-
// Pattern used in code
|
|
114
|
-
const handleError = (error: unknown): string => {
|
|
115
|
-
if (isNotFoundError(error)) return 'not-found'
|
|
116
|
-
if (error instanceof SyntaxError) return 'parse-error'
|
|
117
|
-
return 'other'
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
expect(handleError(fsError)).toBe('not-found')
|
|
121
|
-
expect(handleError(syntaxError)).toBe('parse-error')
|
|
122
|
-
expect(handleError(new Error('Other'))).toBe('other')
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
})
|
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Helper Tests
|
|
3
|
-
* Tests for centralized date operations and formatting
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it, setSystemTime } from 'bun:test'
|
|
7
|
-
import {
|
|
8
|
-
calculateDuration,
|
|
9
|
-
formatDate,
|
|
10
|
-
formatDuration,
|
|
11
|
-
formatMonth,
|
|
12
|
-
getDateKey,
|
|
13
|
-
getDateRange,
|
|
14
|
-
getDaysAgo,
|
|
15
|
-
getDaysFromNow,
|
|
16
|
-
getEndOfDay,
|
|
17
|
-
getStartOfDay,
|
|
18
|
-
getTimestamp,
|
|
19
|
-
getTodayKey,
|
|
20
|
-
getYearMonthDay,
|
|
21
|
-
isToday,
|
|
22
|
-
isWithinLastDays,
|
|
23
|
-
parseDate,
|
|
24
|
-
toRelative,
|
|
25
|
-
} from '../../utils/date-helper'
|
|
26
|
-
|
|
27
|
-
describe('DateHelper', () => {
|
|
28
|
-
describe('formatDate', () => {
|
|
29
|
-
it('should format date to YYYY-MM-DD', () => {
|
|
30
|
-
const date = new Date(2025, 9, 4) // Oct 4, 2025
|
|
31
|
-
expect(formatDate(date)).toBe('2025-10-04')
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('should pad single digit months', () => {
|
|
35
|
-
const date = new Date(2025, 0, 15) // Jan 15, 2025
|
|
36
|
-
expect(formatDate(date)).toBe('2025-01-15')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('should pad single digit days', () => {
|
|
40
|
-
const date = new Date(2025, 11, 5) // Dec 5, 2025
|
|
41
|
-
expect(formatDate(date)).toBe('2025-12-05')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('should handle year boundaries', () => {
|
|
45
|
-
const date = new Date(2024, 11, 31) // Dec 31, 2024
|
|
46
|
-
expect(formatDate(date)).toBe('2024-12-31')
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('formatMonth', () => {
|
|
51
|
-
it('should format date to YYYY-MM', () => {
|
|
52
|
-
const date = new Date(2025, 9, 15) // Oct 15, 2025
|
|
53
|
-
expect(formatMonth(date)).toBe('2025-10')
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should pad single digit months', () => {
|
|
57
|
-
const date = new Date(2025, 2, 1) // Mar 1, 2025
|
|
58
|
-
expect(formatMonth(date)).toBe('2025-03')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('should handle December', () => {
|
|
62
|
-
const date = new Date(2025, 11, 25) // Dec 25, 2025
|
|
63
|
-
expect(formatMonth(date)).toBe('2025-12')
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
describe('getTodayKey', () => {
|
|
68
|
-
it('should return today in YYYY-MM-DD format', () => {
|
|
69
|
-
setSystemTime(new Date(2025, 5, 15)) // June 15, 2025
|
|
70
|
-
expect(getTodayKey()).toBe('2025-06-15')
|
|
71
|
-
setSystemTime()
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
describe('getDateKey', () => {
|
|
76
|
-
it('should return date in YYYY-MM-DD format (alias for formatDate)', () => {
|
|
77
|
-
const date = new Date(2025, 7, 20) // Aug 20, 2025
|
|
78
|
-
expect(getDateKey(date)).toBe('2025-08-20')
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
describe('getYearMonthDay', () => {
|
|
83
|
-
it('should return separate year, month, day strings', () => {
|
|
84
|
-
const date = new Date(2025, 9, 4) // Oct 4, 2025
|
|
85
|
-
const result = getYearMonthDay(date)
|
|
86
|
-
|
|
87
|
-
expect(result.year).toBe('2025')
|
|
88
|
-
expect(result.month).toBe('10')
|
|
89
|
-
expect(result.day).toBe('04')
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('should pad month values', () => {
|
|
93
|
-
const date = new Date(2025, 0, 15) // Jan 15, 2025
|
|
94
|
-
const result = getYearMonthDay(date)
|
|
95
|
-
expect(result.month).toBe('01')
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should pad day values', () => {
|
|
99
|
-
const date = new Date(2025, 5, 7) // June 7, 2025
|
|
100
|
-
const result = getYearMonthDay(date)
|
|
101
|
-
expect(result.day).toBe('07')
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
describe('parseDate', () => {
|
|
106
|
-
it('should parse YYYY-MM-DD format', () => {
|
|
107
|
-
const result = parseDate('2025-10-04')
|
|
108
|
-
expect(result.getFullYear()).toBe(2025)
|
|
109
|
-
expect(result.getMonth()).toBe(9) // 0-indexed
|
|
110
|
-
expect(result.getDate()).toBe(4)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('should parse ISO strings', () => {
|
|
114
|
-
const result = parseDate('2025-10-04T14:30:00.000Z')
|
|
115
|
-
expect(result.getFullYear()).toBe(2025)
|
|
116
|
-
expect(result.getMonth()).toBe(9)
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
describe('getTimestamp', () => {
|
|
121
|
-
it('should return ISO timestamp', () => {
|
|
122
|
-
setSystemTime(new Date('2025-10-04T14:30:00.000Z'))
|
|
123
|
-
expect(getTimestamp()).toBe('2025-10-04T14:30:00.000Z')
|
|
124
|
-
setSystemTime()
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('should include milliseconds', () => {
|
|
128
|
-
const timestamp = getTimestamp()
|
|
129
|
-
expect(timestamp).toMatch(/\.\d{3}Z$/)
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
describe('getDaysAgo', () => {
|
|
134
|
-
beforeEach(() => {
|
|
135
|
-
setSystemTime(new Date(2025, 9, 15)) // Oct 15, 2025
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
afterEach(() => {
|
|
139
|
-
setSystemTime()
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('should calculate past dates correctly', () => {
|
|
143
|
-
const result = getDaysAgo(5)
|
|
144
|
-
expect(formatDate(result)).toBe('2025-10-10')
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
it('should handle month boundaries', () => {
|
|
148
|
-
const result = getDaysAgo(20)
|
|
149
|
-
expect(formatDate(result)).toBe('2025-09-25')
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('should return today for 0 days ago', () => {
|
|
153
|
-
const result = getDaysAgo(0)
|
|
154
|
-
expect(formatDate(result)).toBe('2025-10-15')
|
|
155
|
-
})
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
describe('getDaysFromNow', () => {
|
|
159
|
-
beforeEach(() => {
|
|
160
|
-
setSystemTime(new Date(2025, 9, 15)) // Oct 15, 2025
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
afterEach(() => {
|
|
164
|
-
setSystemTime()
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
it('should calculate future dates correctly', () => {
|
|
168
|
-
const result = getDaysFromNow(5)
|
|
169
|
-
expect(formatDate(result)).toBe('2025-10-20')
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
it('should handle month boundaries', () => {
|
|
173
|
-
const result = getDaysFromNow(20)
|
|
174
|
-
expect(formatDate(result)).toBe('2025-11-04')
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
it('should return today for 0 days from now', () => {
|
|
178
|
-
const result = getDaysFromNow(0)
|
|
179
|
-
expect(formatDate(result)).toBe('2025-10-15')
|
|
180
|
-
})
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
describe('getDateRange', () => {
|
|
184
|
-
it('should return array of dates in range', () => {
|
|
185
|
-
const from = new Date(2025, 9, 1) // Oct 1
|
|
186
|
-
const to = new Date(2025, 9, 5) // Oct 5
|
|
187
|
-
|
|
188
|
-
const result = getDateRange(from, to)
|
|
189
|
-
|
|
190
|
-
expect(result.length).toBe(5)
|
|
191
|
-
expect(formatDate(result[0])).toBe('2025-10-01')
|
|
192
|
-
expect(formatDate(result[4])).toBe('2025-10-05')
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
it('should include start and end dates', () => {
|
|
196
|
-
const from = new Date(2025, 9, 10)
|
|
197
|
-
const to = new Date(2025, 9, 12)
|
|
198
|
-
|
|
199
|
-
const result = getDateRange(from, to)
|
|
200
|
-
|
|
201
|
-
expect(formatDate(result[0])).toBe('2025-10-10')
|
|
202
|
-
expect(formatDate(result[result.length - 1])).toBe('2025-10-12')
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('should return single date if from equals to', () => {
|
|
206
|
-
const date = new Date(2025, 9, 15)
|
|
207
|
-
const result = getDateRange(date, date)
|
|
208
|
-
|
|
209
|
-
expect(result.length).toBe(1)
|
|
210
|
-
expect(formatDate(result[0])).toBe('2025-10-15')
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
it('should handle month boundaries', () => {
|
|
214
|
-
const from = new Date(2025, 9, 30) // Oct 30
|
|
215
|
-
const to = new Date(2025, 10, 2) // Nov 2
|
|
216
|
-
|
|
217
|
-
const result = getDateRange(from, to)
|
|
218
|
-
|
|
219
|
-
expect(result.length).toBe(4)
|
|
220
|
-
expect(formatDate(result[0])).toBe('2025-10-30')
|
|
221
|
-
expect(formatDate(result[3])).toBe('2025-11-02')
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
it('should return empty array if from is after to', () => {
|
|
225
|
-
const from = new Date(2025, 9, 15)
|
|
226
|
-
const to = new Date(2025, 9, 10)
|
|
227
|
-
|
|
228
|
-
const result = getDateRange(from, to)
|
|
229
|
-
|
|
230
|
-
expect(result.length).toBe(0)
|
|
231
|
-
})
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
describe('isToday', () => {
|
|
235
|
-
beforeEach(() => {
|
|
236
|
-
setSystemTime(new Date(2025, 9, 15)) // Oct 15, 2025
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
afterEach(() => {
|
|
240
|
-
setSystemTime()
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
it('should return true for today', () => {
|
|
244
|
-
const today = new Date(2025, 9, 15)
|
|
245
|
-
expect(isToday(today)).toBe(true)
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
it('should return false for yesterday', () => {
|
|
249
|
-
const yesterday = new Date(2025, 9, 14)
|
|
250
|
-
expect(isToday(yesterday)).toBe(false)
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
it('should return false for tomorrow', () => {
|
|
254
|
-
const tomorrow = new Date(2025, 9, 16)
|
|
255
|
-
expect(isToday(tomorrow)).toBe(false)
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
it('should ignore time component', () => {
|
|
259
|
-
const todayLate = new Date(2025, 9, 15, 23, 59, 59)
|
|
260
|
-
expect(isToday(todayLate)).toBe(true)
|
|
261
|
-
})
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
describe('isWithinLastDays', () => {
|
|
265
|
-
beforeEach(() => {
|
|
266
|
-
setSystemTime(new Date(2025, 9, 15, 12, 0, 0)) // Oct 15, 2025 at noon
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
afterEach(() => {
|
|
270
|
-
setSystemTime()
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
it('should return true for dates within range', () => {
|
|
274
|
-
const recent = new Date(2025, 9, 12) // 3 days ago
|
|
275
|
-
expect(isWithinLastDays(recent, 7)).toBe(true)
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
it('should return false for dates outside range', () => {
|
|
279
|
-
const old = new Date(2025, 9, 1) // 14 days ago
|
|
280
|
-
expect(isWithinLastDays(old, 7)).toBe(false)
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
it('should include today', () => {
|
|
284
|
-
const today = new Date(2025, 9, 15)
|
|
285
|
-
expect(isWithinLastDays(today, 7)).toBe(true)
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
it('should include boundary date', () => {
|
|
289
|
-
// Oct 8 at noon is exactly 7 days before Oct 15 at noon
|
|
290
|
-
const boundary = new Date(2025, 9, 8, 12, 0, 0)
|
|
291
|
-
expect(isWithinLastDays(boundary, 7)).toBe(true)
|
|
292
|
-
})
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
describe('formatDuration', () => {
|
|
296
|
-
it('should format seconds', () => {
|
|
297
|
-
expect(formatDuration(5000)).toBe('5s')
|
|
298
|
-
expect(formatDuration(45000)).toBe('45s')
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
it('should format minutes', () => {
|
|
302
|
-
expect(formatDuration(60000)).toBe('1m')
|
|
303
|
-
expect(formatDuration(120000)).toBe('2m')
|
|
304
|
-
expect(formatDuration(90000)).toBe('1m') // 1.5 min rounds down
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
it('should format hours and minutes', () => {
|
|
308
|
-
expect(formatDuration(3600000)).toBe('1h 0m')
|
|
309
|
-
expect(formatDuration(5400000)).toBe('1h 30m')
|
|
310
|
-
expect(formatDuration(7200000)).toBe('2h 0m')
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
it('should format days and hours', () => {
|
|
314
|
-
expect(formatDuration(86400000)).toBe('1d 0h')
|
|
315
|
-
expect(formatDuration(90000000)).toBe('1d 1h')
|
|
316
|
-
expect(formatDuration(172800000)).toBe('2d 0h')
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
it('should handle zero', () => {
|
|
320
|
-
expect(formatDuration(0)).toBe('0s')
|
|
321
|
-
})
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
describe('calculateDuration', () => {
|
|
325
|
-
it('should calculate duration between two dates', () => {
|
|
326
|
-
const start = new Date('2025-10-15T10:00:00.000Z')
|
|
327
|
-
const end = new Date('2025-10-15T12:30:00.000Z')
|
|
328
|
-
|
|
329
|
-
expect(calculateDuration(start, end)).toBe('2h 30m')
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
it('should default to now if no end date', () => {
|
|
333
|
-
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
334
|
-
|
|
335
|
-
const start = new Date('2025-10-15T10:00:00.000Z')
|
|
336
|
-
expect(calculateDuration(start)).toBe('2h 0m')
|
|
337
|
-
|
|
338
|
-
setSystemTime()
|
|
339
|
-
})
|
|
340
|
-
|
|
341
|
-
it('should handle short durations', () => {
|
|
342
|
-
const start = new Date('2025-10-15T10:00:00.000Z')
|
|
343
|
-
const end = new Date('2025-10-15T10:00:30.000Z')
|
|
344
|
-
|
|
345
|
-
expect(calculateDuration(start, end)).toBe('30s')
|
|
346
|
-
})
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
describe('getStartOfDay', () => {
|
|
350
|
-
it('should set time to 00:00:00.000', () => {
|
|
351
|
-
const date = new Date(2025, 9, 15, 14, 30, 45, 500)
|
|
352
|
-
const result = getStartOfDay(date)
|
|
353
|
-
|
|
354
|
-
expect(result.getHours()).toBe(0)
|
|
355
|
-
expect(result.getMinutes()).toBe(0)
|
|
356
|
-
expect(result.getSeconds()).toBe(0)
|
|
357
|
-
expect(result.getMilliseconds()).toBe(0)
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
it('should preserve the date', () => {
|
|
361
|
-
const date = new Date(2025, 9, 15, 23, 59, 59)
|
|
362
|
-
const result = getStartOfDay(date)
|
|
363
|
-
|
|
364
|
-
expect(result.getFullYear()).toBe(2025)
|
|
365
|
-
expect(result.getMonth()).toBe(9)
|
|
366
|
-
expect(result.getDate()).toBe(15)
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
it('should not mutate original date', () => {
|
|
370
|
-
const original = new Date(2025, 9, 15, 14, 30)
|
|
371
|
-
getStartOfDay(original)
|
|
372
|
-
|
|
373
|
-
expect(original.getHours()).toBe(14)
|
|
374
|
-
expect(original.getMinutes()).toBe(30)
|
|
375
|
-
})
|
|
376
|
-
})
|
|
377
|
-
|
|
378
|
-
describe('getEndOfDay', () => {
|
|
379
|
-
it('should set time to 23:59:59.999', () => {
|
|
380
|
-
const date = new Date(2025, 9, 15, 10, 0, 0, 0)
|
|
381
|
-
const result = getEndOfDay(date)
|
|
382
|
-
|
|
383
|
-
expect(result.getHours()).toBe(23)
|
|
384
|
-
expect(result.getMinutes()).toBe(59)
|
|
385
|
-
expect(result.getSeconds()).toBe(59)
|
|
386
|
-
expect(result.getMilliseconds()).toBe(999)
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
it('should preserve the date', () => {
|
|
390
|
-
const date = new Date(2025, 9, 15, 0, 0, 0)
|
|
391
|
-
const result = getEndOfDay(date)
|
|
392
|
-
|
|
393
|
-
expect(result.getFullYear()).toBe(2025)
|
|
394
|
-
expect(result.getMonth()).toBe(9)
|
|
395
|
-
expect(result.getDate()).toBe(15)
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
it('should not mutate original date', () => {
|
|
399
|
-
const original = new Date(2025, 9, 15, 10, 30)
|
|
400
|
-
getEndOfDay(original)
|
|
401
|
-
|
|
402
|
-
expect(original.getHours()).toBe(10)
|
|
403
|
-
expect(original.getMinutes()).toBe(30)
|
|
404
|
-
})
|
|
405
|
-
})
|
|
406
|
-
|
|
407
|
-
describe('toRelative', () => {
|
|
408
|
-
it('should show minutes for dates within 1 hour', () => {
|
|
409
|
-
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
410
|
-
const fiveMinAgo = '2025-10-15T11:55:00.000Z'
|
|
411
|
-
expect(toRelative(fiveMinAgo)).toBe('5 minutes ago')
|
|
412
|
-
setSystemTime()
|
|
413
|
-
})
|
|
414
|
-
|
|
415
|
-
it('should show hours for dates within 24 hours', () => {
|
|
416
|
-
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
417
|
-
const threeHoursAgo = '2025-10-15T09:00:00.000Z'
|
|
418
|
-
expect(toRelative(threeHoursAgo)).toBe('3 hours ago')
|
|
419
|
-
setSystemTime()
|
|
420
|
-
})
|
|
421
|
-
|
|
422
|
-
it('should show days for dates within 7 days', () => {
|
|
423
|
-
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
424
|
-
const twoDaysAgo = '2025-10-13T12:00:00.000Z'
|
|
425
|
-
expect(toRelative(twoDaysAgo)).toBe('2 days ago')
|
|
426
|
-
setSystemTime()
|
|
427
|
-
})
|
|
428
|
-
|
|
429
|
-
it('should show months for dates older than 30 days', () => {
|
|
430
|
-
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
431
|
-
const twoMonthsAgo = '2025-08-15T12:00:00.000Z'
|
|
432
|
-
expect(toRelative(twoMonthsAgo)).toBe('2 months ago')
|
|
433
|
-
setSystemTime()
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
it('should accept Date objects', () => {
|
|
437
|
-
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
438
|
-
const date = new Date('2025-10-15T11:00:00.000Z')
|
|
439
|
-
expect(toRelative(date)).toBe('1 hour ago')
|
|
440
|
-
setSystemTime()
|
|
441
|
-
})
|
|
442
|
-
|
|
443
|
-
it('should accept ISO string timestamps', () => {
|
|
444
|
-
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
445
|
-
expect(toRelative('2025-10-14T12:00:00.000Z')).toBe('1 day ago')
|
|
446
|
-
setSystemTime()
|
|
447
|
-
})
|
|
448
|
-
})
|
|
449
|
-
})
|