time_helper.rb 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. module TimeHelperCache
  3. %w[travel travel_to freeze_time travel_back].each do |method_name|
  4. define_method method_name do |*args, **kwargs, &blk|
  5. super(*args, **kwargs, &blk).tap do
  6. Rails.cache.clear
  7. rescue Errno::EISDIR
  8. # suppress race condition errors
  9. ensure
  10. Setting.class_variable_set :@@last_changed_at, 1.second.ago # rubocop:disable Style/ClassVars
  11. end
  12. end
  13. end
  14. # Similar to #travel_to, but fakes browser (frontend) time.
  15. # Useful when testing time that is generated in frontend
  16. def browser_travel_to(time)
  17. execute_script "window.clock = sinon.useFakeTimers({now: new Date(#{time.to_i * 1_000}), toFake: ['Date']})"
  18. end
  19. # Reimplementation of `setMonth(month[, date])` from the ECMAScript specification.
  20. # https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date.prototype.setmonth
  21. def frontend_relative_month(obj, month, date = nil, year: nil)
  22. # 1. Let t be ? thisTimeValue(this value).
  23. t = obj
  24. # 2. Let m be ? ToNumber(month).
  25. m = month.to_i
  26. # 3. If date is present, let dt be ? ToNumber(date).
  27. if date.present?
  28. dt = date.to_i
  29. end
  30. # 4. If t is NaN, return NaN.
  31. raise InvalidDate if !t.is_a?(Time)
  32. # 5. Set t to LocalTime(t).
  33. t = t.in_time_zone
  34. # 6. If date is not present, let dt be DateFromTime(t).
  35. if date.nil?
  36. dt = t.day
  37. end
  38. # 7. Let newDate be MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t)).
  39. new_year = t.year
  40. new_month = t.month + m
  41. if new_month > 12
  42. new_year += 1
  43. new_month -= 12
  44. end
  45. new_year += year if year
  46. Time.zone.local(new_year, new_month, dt, t.hour, t.min, t.sec)
  47. # Ignore the rest, as `Time#local` already handles it correctly:
  48. # 8. Let u be TimeClip(UTC(newDate)).
  49. # 9. Set the [[DateValue]] internal slot of this Date object to u.
  50. # 10. Return u.
  51. end
  52. end
  53. RSpec.configure do |config|
  54. # make usage of time travel helpers possible
  55. config.include ActiveSupport::Testing::TimeHelpers
  56. config.include TimeHelperCache
  57. end