Skip timeago elements with an unparsable datetime
What does this MR do and why?
Server-rendered <time class="js-timeago"> elements are enhanced on page load by localTimeAgo. It replaces the text with a relative time ("2 days ago") and sets a tooltip with the absolute date via Intl.DateTimeFormat.
The gitlab-test fixture repository contains a commit with a committer date of year 292277024627, beyond the range JavaScript Date accepts. new Date() returns an Invalid Date. Intl.DateTimeFormat.format then throws RangeError: Invalid time value inside the idle callback, so the error is uncaught.
In feature specs this logged Uncaught RangeError: Invalid time value in 14 examples across 6 spec files. All of them render a branch or commit list that includes that commit:
spec/features/projects/branches_spec.rbspec/features/projects/branches/user_views_branches_spec.rbspec/features/projects/branches/user_deletes_branch_spec.rbspec/features/protected_branches_spec.rbee/spec/features/projects/protected_branches_spec.rbspec/features/projects/members/member_leaves_project_spec.rb
Real-world relevance: git allows any 64-bit committer timestamp, so a real repository can contain such a commit and break the other timestamps on its pages.
The fix filters the elements to those whose datetime parses to a valid Date, with the existing isValidDate helper. Invalid elements keep their server-rendered text and title. Valid elements render as before. This mirrors what initLocalDateTimes and the print handler in the same file already do with a try/catch.
The Vue component TimeAgoTooltip has the same problem on its own path. Its tooltipText computed calls Intl.DateTimeFormat through the timeago mixin, so an invalid time prop throws during render. This is the stack trace in the Sentry issue linked below. Following review feedback, the component now checks isValidDate too. An invalid time renders as its raw value with no tooltip. The commit list page had a local guard around the component for the same case, added in !233945 (merged). That guard is removed, because the component now covers it. The other two guards from that MR stay, because they format dates without the component.
Changes made:
app/assets/javascripts/lib/utils/datetime/timeago_utility.js— filter to parsable elements before rendering text and tooltipsspec/frontend/lib/utils/datetime/timeago_utility_spec.js— new block "when an element has a datetime that cannot be parsed" with two cases: the invalid element keeps its text and title and nothing throws; a sibling valid element still rendersapp/assets/javascripts/vue_shared/components/time_ago_tooltip.vue— new computedisParsable; an invalidtimerenders as raw text with notitleoraria-labelspec/frontend/vue_shared/components/time_ago_tooltip_spec.js— new block "when time cannot be parsed"app/assets/javascripts/projects/commits/components/commit_list_item.vue— remove thehasParsableAuthoredDateguard and fallback<span>; render<timeago-tooltip>unconditionallyspec/frontend/projects/commits/components/commit_list_item_spec.js— remove the fallback block now covered by the component spec
How to set up and validate locally
-
Use a project that contains the gitlab-test repository. The default GDK seed project "gitlab-test" has the branch
spooky-stuff. -
Open Code > Branches > All.
-
Open the browser DevTools console.
-
Check there is no
RangeError: Invalid time value. -
Check the
spooky-stuffrow still shows the date text "Dec 06, 292277024627".
-
Check the other rows show relative times with tooltips.
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
- I have evaluated the MR acceptance checklist for this MR.
References
- Addresses one entry of #628901 (browser console error catalogue, section B)
- Errors surfaced by !255207 (closed) (feature specs fail on console errors)
- Sibling fix from the same catalogue: !255305 (merged)
- Fixture commit with the out-of-range date: gitlab-test@ba3343bc
- Component guard suggested in !255309 (comment 3831892346)
- Earlier page-level guard this MR generalizes: !233945 (merged)
- Sentry error on the component path, can be closed after merge: https://gitlab.com/gitlab-org/frontend/duo-sentry-insights/-/work_items/64
