diff --git a/test/controllers/boards/columns_controller_test.rb b/test/controllers/boards/columns_controller_test.rb index f76a3ae80..7c6e7f525 100644 --- a/test/controllers/boards/columns_controller_test.rb +++ b/test/controllers/boards/columns_controller_test.rb @@ -16,7 +16,7 @@ class Boards::ColumnsControllerTest < ActionDispatch::IntegrationTest assert_response :success end - assert_equal "New Column", boards(:writebook).columns.order(created_at: :desc).first.name + assert_equal "New Column", boards(:writebook).columns.last.name end test "update" do diff --git a/test/controllers/boards_controller_test.rb b/test/controllers/boards_controller_test.rb index 2a94e524e..3729f09c7 100644 --- a/test/controllers/boards_controller_test.rb +++ b/test/controllers/boards_controller_test.rb @@ -20,7 +20,7 @@ class BoardsControllerTest < ActionDispatch::IntegrationTest post boards_path, params: { board: { name: "Remodel Punch List" } } end - board = Board.order(created_at: :desc).first + board = Board.last assert_redirected_to board_path(board) assert_includes board.users, users(:kevin) assert_equal "Remodel Punch List", board.name diff --git a/test/controllers/cards/publishes_controller_test.rb b/test/controllers/cards/publishes_controller_test.rb index 4b8e7930f..4de6d20bb 100644 --- a/test/controllers/cards/publishes_controller_test.rb +++ b/test/controllers/cards/publishes_controller_test.rb @@ -26,7 +26,7 @@ class Cards::PublishesControllerTest < ActionDispatch::IntegrationTest end end - new_card = Card.order(created_at: :desc).first + new_card = Card.last assert new_card.drafted? assert_redirected_to new_card end diff --git a/test/controllers/cards_controller_test.rb b/test/controllers/cards_controller_test.rb index 56ed20308..ca60a714a 100644 --- a/test/controllers/cards_controller_test.rb +++ b/test/controllers/cards_controller_test.rb @@ -20,7 +20,7 @@ class CardsControllerTest < ActionDispatch::IntegrationTest post board_cards_path(boards(:writebook)) end - card = Card.order(created_at: :desc).first + card = Card.last assert card.drafted? assert_redirected_to card end diff --git a/test/controllers/filters_controller_test.rb b/test/controllers/filters_controller_test.rb index 6f687f790..48dab9d75 100644 --- a/test/controllers/filters_controller_test.rb +++ b/test/controllers/filters_controller_test.rb @@ -16,7 +16,7 @@ class FiltersControllerTest < ActionDispatch::IntegrationTest end assert_response :success - filter = Filter.order(created_at: :desc).first + filter = Filter.last assert_predicate filter.indexed_by, :closed? assert_predicate filter.assignment_status, :unassigned? assert_equal [ tags(:mobile) ], filter.tags diff --git a/test/controllers/webhooks_controller_test.rb b/test/controllers/webhooks_controller_test.rb index 407697191..2cd427b5b 100644 --- a/test/controllers/webhooks_controller_test.rb +++ b/test/controllers/webhooks_controller_test.rb @@ -35,7 +35,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest } end - webhook = Webhook.order(created_at: :desc).first + webhook = Webhook.last assert_redirected_to board_webhook_path(webhook.board, webhook) assert_equal board, webhook.board diff --git a/test/models/card/closeable_test.rb b/test/models/card/closeable_test.rb index 8e0b9e59d..21926aa6e 100644 --- a/test/models/card/closeable_test.rb +++ b/test/models/card/closeable_test.rb @@ -18,7 +18,7 @@ class Card::CloseableTest < ActiveSupport::TestCase end assert cards(:logo).closed? - assert cards(:logo).events.order(created_at: :desc).first.action.card_closed? + assert cards(:logo).events.last.action.card_closed? assert_equal users(:kevin), cards(:logo).closed_by end @@ -29,6 +29,6 @@ class Card::CloseableTest < ActiveSupport::TestCase cards(:shipping).reopen end assert cards(:shipping).reload.open? - assert cards(:shipping).events.order(created_at: :desc).first.action.card_reopened? + assert cards(:shipping).events.last.action.card_reopened? end end diff --git a/test/models/card/eventable/system_commenter_test.rb b/test/models/card/eventable/system_commenter_test.rb index 11b01efeb..57bef880b 100644 --- a/test/models/card/eventable/system_commenter_test.rb +++ b/test/models/card/eventable/system_commenter_test.rb @@ -45,7 +45,7 @@ class Card::Eventable::SystemCommenterTest < ActiveSupport::TestCase def assert_system_comment(expected_comment) assert_difference -> { @card.comments.count }, 1 do yield - comment = @card.comments.order(created_at: :desc).first + comment = @card.comments.last assert comment.creator.system? assert_match Regexp.new(expected_comment.strip, Regexp::IGNORECASE), comment.body.to_plain_text.strip end diff --git a/test/models/card/postponable_test.rb b/test/models/card/postponable_test.rb index 8af3206d3..0bafd3ee8 100644 --- a/test/models/card/postponable_test.rb +++ b/test/models/card/postponable_test.rb @@ -26,7 +26,7 @@ class Card::PostponableTest < ActiveSupport::TestCase end assert_equal users(:david), card.not_now.user - assert card.events.order(created_at: :desc).first.action.card_postponed? + assert card.events.last.action.card_postponed? assert_changes -> { card.reload.postponed? }, to: false do card.resume @@ -42,7 +42,7 @@ class Card::PostponableTest < ActiveSupport::TestCase end end - assert card.events.order(created_at: :desc).first.action.card_auto_postponed? + assert card.events.last.action.card_auto_postponed? end test "scopes" do diff --git a/test/models/card/statuses_test.rb b/test/models/card/statuses_test.rb index fab656483..7d2fa9401 100644 --- a/test/models/card/statuses_test.rb +++ b/test/models/card/statuses_test.rb @@ -34,7 +34,7 @@ class Card::StatusesTest < ActiveSupport::TestCase @card = boards(:writebook).cards.create! creator: users(:kevin), title: "Published Card", status: :published end - event = Event.order(created_at: :desc).first + event = Event.last assert_equal @card, event.eventable assert_equal "card_published", event.action end @@ -47,7 +47,7 @@ class Card::StatusesTest < ActiveSupport::TestCase card.publish end - event = Event.order(created_at: :desc).first + event = Event.last assert_equal card, event.eventable assert_equal "card_published", event.action end diff --git a/test/models/card/taggable_test.rb b/test/models/card/taggable_test.rb index 8b1f59aff..5d054af14 100644 --- a/test/models/card/taggable_test.rb +++ b/test/models/card/taggable_test.rb @@ -10,7 +10,7 @@ class Card::TaggableTest < ActiveSupport::TestCase @card.toggle_tag_with "ruby" end - assert_equal "ruby", @card.tags.order(created_at: :desc).first.title + assert_equal "ruby", @card.tags.last.title assert_difference -> { @card.tags.count }, -1 do @card.toggle_tag_with "ruby" diff --git a/test/models/card_test.rb b/test/models/card_test.rb index de2aab099..180b7ff34 100644 --- a/test/models/card_test.rb +++ b/test/models/card_test.rb @@ -23,7 +23,7 @@ class CardTest < ActiveSupport::TestCase cards(:logo).comments.create!(body: "Agreed.") end - assert_equal "Agreed.", cards(:logo).comments.order(created_at: :desc).first.body.to_plain_text.chomp + assert_equal "Agreed.", cards(:logo).comments.last.body.to_plain_text.chomp end test "assignment states" do @@ -38,7 +38,7 @@ class CardTest < ActiveSupport::TestCase cards(:logo).toggle_assignment users(:kevin) end assert_not cards(:logo).assigned_to?(users(:kevin)) - unassign_event = Event.order(created_at: :desc).first + unassign_event = Event.last assert_equal "card_unassigned", unassign_event.action assert_equal [ users(:kevin) ], unassign_event.assignees @@ -46,7 +46,7 @@ class CardTest < ActiveSupport::TestCase cards(:logo).toggle_assignment users(:kevin) end assert cards(:logo).assigned_to?(users(:kevin)) - assign_event = Event.order(created_at: :desc).first + assign_event = Event.last assert_equal "card_assigned", assign_event.action assert_equal [ users(:kevin) ], assign_event.assignees end diff --git a/test/models/notifier/event_notifier_test.rb b/test/models/notifier/event_notifier_test.rb index 1f2a6ff92..bc68b2a6c 100644 --- a/test/models/notifier/event_notifier_test.rb +++ b/test/models/notifier/event_notifier_test.rb @@ -39,7 +39,7 @@ class Notifier::EventNotifierTest < ActiveSupport::TestCase Notifier.for(events(:logo_published)).notify - assert_equal cards(:logo), Notification.order(created_at: :desc).first.source.eventable + assert_equal cards(:logo), Notification.last.source.eventable end test "assignment events only create a notification for the assignee" do diff --git a/test/system/smoke_test.rb b/test/system/smoke_test.rb index 9db9b477e..92cb287fd 100644 --- a/test/system/smoke_test.rb +++ b/test/system/smoke_test.rb @@ -40,7 +40,6 @@ class SmokeTest < ApplicationSystemTestCase notif = notifications(:logo_comment_david_mention_by_jz) - skip("Grouped notifications and the new UUID ids are making this test flaky") assert_selector "div##{dom_id(notif)}" within_window(open_new_window) { visit card_url(notif.card) } diff --git a/test/test_helper.rb b/test/test_helper.rb index be753cb74..a06b9737f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -94,19 +94,20 @@ module FixturesTestHelper # so that UUIDs sort in the same order as integer IDs fixture_int = Zlib.crc32("fixtures/#{label}") % (2**30 - 1) - # Use fixture_int as second offset from a fixed base time (1 year before 2025-01-01) - # This ensures all fixtures are in the past, and new test records are newest + # Translate the deterministic order into times in the past, so that records + # created during test runs are also always newer than the fixtures. base_time = Time.utc(2024, 1, 1, 0, 0, 0) - timestamp = base_time + fixture_int.seconds + timestamp = base_time + (fixture_int / 1000.0) uuid_v7_with_timestamp(timestamp, label) end def uuid_v7_with_timestamp(time, seed_string) # Generate UUIDv7 with custom timestamp and deterministic random bits - # Format: 48-bit timestamp_ms | 12-bit random | 4-bit version | 62-bit random + # Format: 48-bit timestamp_ms | 12-bit sub_ms_precision | 4-bit version | 62-bit random - timestamp_ms = (time.to_f * 1000).to_i + time_ms = time.to_f * 1000 + timestamp_ms = time_ms.to_i # 48-bit timestamp (milliseconds since epoch) bytes = [] @@ -117,13 +118,18 @@ module FixturesTestHelper bytes[4] = (timestamp_ms >> 8) & 0xff bytes[5] = timestamp_ms & 0xff - # Derive deterministic "random" bits from seed_string + # Use the 12-bit rand_a field for sub-millisecond precision + # Extract fractional milliseconds and convert to 12-bit value (0-4095) + # This gives us ~0.244 microsecond precision + frac_ms = time_ms - timestamp_ms + sub_ms_precision = (frac_ms * 4096).to_i & 0xfff + + # Derive deterministic "random" bits from seed_string for the remaining random bits hash = Digest::MD5.hexdigest(seed_string) - # 12-bit random + 4-bit version (0111 for v7) - rand_a = hash[0...3].to_i(16) & 0xfff - bytes[6] = ((rand_a >> 8) & 0x0f) | 0x70 # version 7 - bytes[7] = rand_a & 0xff + # 12-bit sub-ms precision + 4-bit version (0111 for v7) + bytes[6] = ((sub_ms_precision >> 8) & 0x0f) | 0x70 # version 7 + bytes[7] = sub_ms_precision & 0xff # 2-bit variant (10) + 62-bit random rand_b = hash[3...19].to_i(16) & ((2**62) - 1)