discourse-ai/spec/lib/modules/ai_helper/date_formatter_spec.rb

261 lines
9.3 KiB
Ruby

# frozen_string_literal: true
RSpec.describe DiscourseAi::AiHelper::DateFormatter do
fab!(:user)
# Reference time is Tuesday Jan 16th, 2024 at 2:30 PM Sydney time
let(:sydney_reference) { DateTime.parse("2024-01-16 14:30:00 +11:00") }
describe ".process_date_placeholders" do
describe "with Sydney timezone" do
before do
user.user_option.update!(timezone: "Australia/Sydney")
freeze_time(sydney_reference)
end
describe "date_time_offset_minutes" do
it "handles minute offsets" do
expect(
described_class.process_date_placeholders(
"Meeting in {{date_time_offset_minutes:30}}",
user,
),
).to eq("Meeting in [date=2024-01-16 time=15:00:00 timezone=\"Australia/Sydney\"]")
expect(
described_class.process_date_placeholders(
"Meeting in {{date_time_offset_minutes:90}}",
user,
),
).to eq("Meeting in [date=2024-01-16 time=16:00:00 timezone=\"Australia/Sydney\"]")
end
it "handles minute ranges" do
expect(
described_class.process_date_placeholders(
"Meeting {{date_time_offset_minutes:60:180}}",
user,
),
).to eq(
"Meeting [date-range from=2024-01-16T15:30:00 to=2024-01-16T17:30:00 timezone=\"Australia/Sydney\"]",
)
end
end
describe "date_offset_days" do
it "handles day offsets" do
expect(
described_class.process_date_placeholders("Due {{date_offset_days:1}}", user),
).to eq("Due [date=2024-01-17 timezone=\"Australia/Sydney\"]")
expect(
described_class.process_date_placeholders("Due {{date_offset_days:7}}", user),
).to eq("Due [date=2024-01-23 timezone=\"Australia/Sydney\"]")
end
it "handles day ranges" do
expect(
described_class.process_date_placeholders("Event {{date_offset_days:1:3}}", user),
).to eq("Event [date-range from=2024-01-17 to=2024-01-19 timezone=\"Australia/Sydney\"]")
end
end
describe "datetime" do
it "handles absolute times today" do
expect(
described_class.process_date_placeholders("Meeting at {{datetime:2pm}}", user),
).to eq("Meeting at [date=2024-01-16 time=14:00:00 timezone=\"Australia/Sydney\"]")
expect(
described_class.process_date_placeholders("Meeting at {{datetime:10pm}}", user),
).to eq("Meeting at [date=2024-01-16 time=22:00:00 timezone=\"Australia/Sydney\"]")
end
it "handles absolute times with day offset" do
expect(
described_class.process_date_placeholders("Meeting {{datetime:2pm+1}}", user),
).to eq("Meeting [date=2024-01-17 time=14:00:00 timezone=\"Australia/Sydney\"]")
end
it "handles time ranges" do
expect(
described_class.process_date_placeholders("Meeting {{datetime:2pm:4pm}}", user),
).to eq(
"Meeting [date-range from=2024-01-16T14:00:00 to=2024-01-16T16:00:00 timezone=\"Australia/Sydney\"]",
)
end
it "handles time ranges with day offsets" do
expect(
described_class.process_date_placeholders("Meeting {{datetime:2pm+1:4pm+1}}", user),
).to eq(
"Meeting [date-range from=2024-01-17T14:00:00 to=2024-01-17T16:00:00 timezone=\"Australia/Sydney\"]",
)
end
it "handles 12-hour time edge cases" do
expect(described_class.process_date_placeholders("At {{datetime:12am}}", user)).to eq(
"At [date=2024-01-16 time=00:00:00 timezone=\"Australia/Sydney\"]",
)
expect(described_class.process_date_placeholders("At {{datetime:12pm}}", user)).to eq(
"At [date=2024-01-16 time=12:00:00 timezone=\"Australia/Sydney\"]",
)
end
end
describe "next_week" do
it "handles next week days" do
expect(
described_class.process_date_placeholders("Meeting {{next_week:tuesday}}", user),
).to eq("Meeting [date=2024-01-23 timezone=\"Australia/Sydney\"]")
end
it "handles next week with specific times" do
expect(
described_class.process_date_placeholders("Meeting {{next_week:tuesday-2pm}}", user),
).to eq("Meeting [date=2024-01-23 time=14:00:00 timezone=\"Australia/Sydney\"]")
end
it "handles next week time ranges" do
expect(
described_class.process_date_placeholders(
"Meeting {{next_week:tuesday-1pm:tuesday-3pm}}",
user,
),
).to eq(
"Meeting [date-range from=2024-01-23T13:00:00 to=2024-01-23T15:00:00 timezone=\"Australia/Sydney\"]",
)
end
end
end
describe "with Los Angeles timezone" do
before do
user.user_option.update!(timezone: "America/Los_Angeles")
# Still freeze at Sydney time, but formatter should work in LA time
freeze_time(sydney_reference)
end
it "handles current time conversions" do
# When it's 2:30 PM Tuesday in Sydney
# It's 7:30 PM Monday in LA
expect(
described_class.process_date_placeholders(
"Meeting {{date_time_offset_minutes:30}}",
user,
),
).to eq("Meeting [date=2024-01-15 time=20:00:00 timezone=\"America/Los_Angeles\"]")
end
it "handles absolute times" do
expect(described_class.process_date_placeholders("Meeting {{datetime:2pm}}", user)).to eq(
"Meeting [date=2024-01-15 time=14:00:00 timezone=\"America/Los_Angeles\"]",
)
end
describe "next_week" do
it "handles next week days in LA time" do
# From Monday night in LA (Tuesday in Sydney)
expect(
described_class.process_date_placeholders("Meeting {{next_week:tuesday}}", user),
).to eq("Meeting [date=2024-01-23 timezone=\"America/Los_Angeles\"]")
end
it "handles next week with specific times in LA" do
expect(
described_class.process_date_placeholders("Meeting {{next_week:tuesday-2pm}}", user),
).to eq("Meeting [date=2024-01-23 time=14:00:00 timezone=\"America/Los_Angeles\"]")
end
it "handles next week time ranges in LA" do
expect(
described_class.process_date_placeholders(
"Meeting {{next_week:tuesday-1pm:tuesday-3pm}}",
user,
),
).to eq(
"Meeting [date-range from=2024-01-23T13:00:00 to=2024-01-23T15:00:00 timezone=\"America/Los_Angeles\"]",
)
end
end
it "handles day transitions across timezones" do
expect(described_class.process_date_placeholders("Due {{date_offset_days:1}}", user)).to eq(
"Due [date=2024-01-16 timezone=\"America/Los_Angeles\"]",
)
end
end
describe "with UTC timezone" do
before do
user.user_option.update!(timezone: nil) # defaults to UTC
freeze_time(sydney_reference)
end
it "defaults to UTC for users without timezone" do
# When it's 2:30 PM in Sydney
# It's 3:30 AM in UTC
expect(
described_class.process_date_placeholders(
"Meeting {{date_time_offset_minutes:30}}",
user,
),
).to eq("Meeting [date=2024-01-16 time=04:00:00 timezone=\"UTC\"]")
end
describe "next_week" do
it "handles next week calculations in UTC" do
expect(
described_class.process_date_placeholders("Meeting {{next_week:tuesday-2pm}}", user),
).to eq("Meeting [date=2024-01-23 time=14:00:00 timezone=\"UTC\"]")
end
end
end
describe "error handling" do
before do
user.user_option.update!(timezone: "Australia/Sydney")
freeze_time(sydney_reference)
end
it "raises on invalid day name" do
expect {
described_class.process_date_placeholders("Meeting {{next_week:notaday}}", user)
}.to raise_error(ArgumentError)
end
it "raises on invalid time format" do
expect {
described_class.process_date_placeholders("Meeting {{datetime:25pm}}", user)
}.to raise_error(ArgumentError)
end
end
describe "mixed formats" do
before do
user.user_option.update!(timezone: "Australia/Sydney")
freeze_time(sydney_reference)
end
it "handles multiple different formats in the same text" do
input = [
"Meeting {{datetime:2pm+1}},",
"duration {{date_time_offset_minutes:60:180}},",
"repeats until {{date_offset_days:7}}",
"with sessions {{next_week:tuesday-1pm:tuesday-3pm}}",
].join(" ")
expected = [
"Meeting [date=2024-01-17 time=14:00:00 timezone=\"Australia/Sydney\"],",
"duration [date-range from=2024-01-16T15:30:00 to=2024-01-16T17:30:00 timezone=\"Australia/Sydney\"],",
"repeats until [date=2024-01-23 timezone=\"Australia/Sydney\"]",
"with sessions [date-range from=2024-01-23T13:00:00 to=2024-01-23T15:00:00 timezone=\"Australia/Sydney\"]",
].join(" ")
expect(described_class.process_date_placeholders(input, user)).to eq(expected)
end
end
end
end