Discover request surface — taste-aware, rotating, snoozable, tag-targeted (milestone #268) #116
@@ -119,8 +119,15 @@ data class SuggestionSnoozeRef(
|
|||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val MILLIS_PER_DAY = 86_400_000.0
|
const val MILLIS_PER_DAY = 86_400_000.0
|
||||||
|
|
||||||
// Below this, days read more naturally than a rounded month count.
|
// Below this, days read more naturally than a rounded month count.
|
||||||
const val DAYS_BEFORE_MONTHS = 45
|
//
|
||||||
|
// Must be <= DAYS_PER_MONTH, or the singular "in about a month" is
|
||||||
|
// unreachable: a rounded month count of 1 needs 15..44 days, and any
|
||||||
|
// threshold above 30 sends all of those down the days branch instead.
|
||||||
|
// This was 45 and the singular branch was dead code — the unit test
|
||||||
|
// for it is what surfaced that.
|
||||||
|
const val DAYS_BEFORE_MONTHS = 30
|
||||||
const val DAYS_PER_MONTH = 30.0
|
const val DAYS_PER_MONTH = 30.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,22 @@ class SuggestionSnoozeRefTest {
|
|||||||
assertEquals("in 14 days", snoozeIn(14.0).returnsIn(now))
|
assertEquals("in 14 days", snoozeIn(14.0).returnsIn(now))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pins the days→months boundary. The singular branch was originally dead
|
||||||
|
// code because the threshold (45) sat above the divisor (30), so no day
|
||||||
|
// count could ever round to one month without being caught by the days
|
||||||
|
// branch first. Asserting both sides of the seam keeps that from
|
||||||
|
// regressing silently.
|
||||||
|
@Test
|
||||||
|
fun `the days-to-months boundary is exactly at 30 days`() {
|
||||||
|
assertEquals("in 29 days", snoozeIn(29.0).returnsIn(now))
|
||||||
|
assertEquals("in about a month", snoozeIn(30.0).returnsIn(now))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `well past a month still reads in the singular rather than jumping to two`() {
|
||||||
|
assertEquals("in about a month", snoozeIn(40.0).returnsIn(now))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `tomorrow is named, not rendered as 1 days`() {
|
fun `tomorrow is named, not rendered as 1 days`() {
|
||||||
assertEquals("tomorrow", snoozeIn(1.0).returnsIn(now))
|
assertEquals("tomorrow", snoozeIn(1.0).returnsIn(now))
|
||||||
|
|||||||
@@ -66,7 +66,12 @@
|
|||||||
const days = Math.round(ms / 86_400_000);
|
const days = Math.round(ms / 86_400_000);
|
||||||
if (days < 1) return 'today';
|
if (days < 1) return 'today';
|
||||||
if (days === 1) return 'tomorrow';
|
if (days === 1) return 'tomorrow';
|
||||||
if (days < 45) return `in ${days} days`;
|
// The 30 must not exceed the divisor below, or the singular "in about a
|
||||||
|
// month" is unreachable — a rounded month count of 1 needs 15..44 days,
|
||||||
|
// and any higher threshold sends all of those down the days branch. This
|
||||||
|
// read 45 and the singular case was dead code (caught by the Android
|
||||||
|
// unit test for the same logic).
|
||||||
|
if (days < 30) return `in ${days} days`;
|
||||||
const months = Math.round(days / 30);
|
const months = Math.round(days / 30);
|
||||||
return months === 1 ? 'in about a month' : `in about ${months} months`;
|
return months === 1 ? 'in about a month' : `in about ${months} months`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,6 +210,21 @@ describe('SuggestionFeed snooze (#2375)', () => {
|
|||||||
expect(screen.getByText(/back in 14 days/i)).toBeInTheDocument();
|
expect(screen.getByText(/back in 14 days/i)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Pins the days→months seam. The singular branch was originally dead code
|
||||||
|
// here too: the threshold (45) sat above the divisor (30), so no day count
|
||||||
|
// could round to one month without hitting the days branch first. Kept in
|
||||||
|
// lockstep with SuggestionSnoozeRefTest on Android.
|
||||||
|
test('the days-to-months boundary sits at 30 days, so "a month" is reachable', () => {
|
||||||
|
setSuggestions([]);
|
||||||
|
setSnoozes([
|
||||||
|
{ mbid: 'a', name: 'JustUnder', snoozed_until: inDays(29), created_at: inDays(0) },
|
||||||
|
{ mbid: 'b', name: 'JustOver', snoozed_until: inDays(30), created_at: inDays(0) }
|
||||||
|
]);
|
||||||
|
render(SuggestionFeed);
|
||||||
|
expect(screen.getByText(/back in 29 days/i)).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/back in about a month/i)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
test('no snoozed section when nothing is parked', () => {
|
test('no snoozed section when nothing is parked', () => {
|
||||||
setSuggestions([oneSeed]);
|
setSuggestions([oneSeed]);
|
||||||
setSnoozes([]);
|
setSnoozes([]);
|
||||||
|
|||||||
Reference in New Issue
Block a user