11import type { TaskActivity , UserBasic } from "@posthog/shared/domain-types" ;
22import { describe , expect , it } from "vitest" ;
3- import {
4- countUnseenActivity ,
5- mergeTaskActivity ,
6- toTaskActivityItems ,
7- } from "./taskActivity" ;
3+ import { toTaskActivityItems } from "./taskActivity" ;
84
95const ann : UserBasic = {
106 id : 2 ,
@@ -15,6 +11,7 @@ const ann: UserBasic = {
1511
1612function activity ( overrides : Partial < TaskActivity > = { } ) : TaskActivity {
1713 return {
14+ id : "activity-1" ,
1815 task_id : "t1" ,
1916 task_title : "Task t1" ,
2017 channel_id : "c1" ,
@@ -24,14 +21,16 @@ function activity(overrides: Partial<TaskActivity> = {}): TaskActivity {
2421 snippet : "ping @[Me](me@posthog.com)" ,
2522 latest_author : ann ,
2623 latest_message_id : "m1" ,
24+ is_unread : true ,
2725 ...overrides ,
2826 } ;
2927}
3028
3129describe ( "toTaskActivityItems" , ( ) => {
32- it ( "maps activity DTOs to feed items " , ( ) => {
30+ it ( "maps the authoritative activity and unread state " , ( ) => {
3331 expect ( toTaskActivityItems ( [ activity ( ) ] ) ) . toEqual ( [
3432 {
33+ id : "activity-1" ,
3534 taskId : "t1" ,
3635 taskTitle : "Task t1" ,
3736 channelId : "c1" ,
@@ -41,12 +40,13 @@ describe("toTaskActivityItems", () => {
4140 snippet : "ping @[Me](me@posthog.com)" ,
4241 author : ann ,
4342 messageId : "m1" ,
43+ isUnread : true ,
4444 } ,
4545 ] ) ;
4646 } ) ;
4747
48- it ( "labels untitled tasks and tolerates missing channel/author/message " , ( ) => {
49- const items = toTaskActivityItems ( [
48+ it ( "labels untitled tasks and tolerates missing optional values " , ( ) => {
49+ const [ item ] = toTaskActivityItems ( [
5050 activity ( {
5151 task_title : "" ,
5252 channel_id : null ,
@@ -57,7 +57,7 @@ describe("toTaskActivityItems", () => {
5757 snippet : "" ,
5858 } ) ,
5959 ] ) ;
60- expect ( items [ 0 ] ) . toMatchObject ( {
60+ expect ( item ) . toMatchObject ( {
6161 taskTitle : "Untitled task" ,
6262 channelId : null ,
6363 channelName : null ,
@@ -66,87 +66,3 @@ describe("toTaskActivityItems", () => {
6666 } ) ;
6767 } ) ;
6868} ) ;
69-
70- describe ( "countUnseenActivity" , ( ) => {
71- const items = toTaskActivityItems ( [
72- activity ( { task_id : "t2" , activity_at : "2026-07-03T10:00:00Z" } ) ,
73- activity ( { task_id : "t1" , activity_at : "2026-07-01T10:00:00Z" } ) ,
74- ] ) ;
75-
76- it ( "counts everything when never seen" , ( ) => {
77- expect ( countUnseenActivity ( items , null ) ) . toBe ( 2 ) ;
78- } ) ;
79-
80- it ( "counts only rows with activity after the last-seen timestamp" , ( ) => {
81- expect ( countUnseenActivity ( items , "2026-07-02T00:00:00Z" ) ) . toBe ( 1 ) ;
82- expect ( countUnseenActivity ( items , "2026-07-04T00:00:00Z" ) ) . toBe ( 0 ) ;
83- } ) ;
84- } ) ;
85-
86- describe ( "mergeTaskActivity" , ( ) => {
87- it ( "prepends newly-active tasks ahead of the previous page" , ( ) => {
88- const previous = [
89- activity ( { task_id : "t1" , activity_at : "2026-07-01T10:00:00Z" } ) ,
90- ] ;
91- const incoming = [
92- activity ( { task_id : "t2" , activity_at : "2026-07-02T10:00:00Z" } ) ,
93- ] ;
94- expect ( mergeTaskActivity ( previous , incoming ) . map ( ( r ) => r . task_id ) ) . toEqual (
95- [ "t2" , "t1" ] ,
96- ) ;
97- } ) ;
98-
99- it ( "replaces a task's row when its activity advances instead of duplicating it" , ( ) => {
100- const previous = [
101- activity ( {
102- task_id : "t1" ,
103- activity_kind : "mention" ,
104- activity_at : "2026-07-01T10:00:00Z" ,
105- } ) ,
106- ] ;
107- const incoming = [
108- activity ( {
109- task_id : "t1" ,
110- activity_kind : "message" ,
111- snippet : "replied" ,
112- activity_at : "2026-07-02T10:00:00Z" ,
113- } ) ,
114- ] ;
115- const merged = mergeTaskActivity ( previous , incoming ) ;
116- expect ( merged ) . toHaveLength ( 1 ) ;
117- expect ( merged [ 0 ] . activity_kind ) . toBe ( "message" ) ;
118- expect ( merged [ 0 ] . activity_at ) . toBe ( "2026-07-02T10:00:00Z" ) ;
119- } ) ;
120-
121- it ( "keeps the newer row when an older duplicate arrives out of order" , ( ) => {
122- const previous = [
123- activity ( { task_id : "t1" , activity_at : "2026-07-05T10:00:00Z" } ) ,
124- ] ;
125- const incoming = [
126- activity ( { task_id : "t1" , activity_at : "2026-07-01T10:00:00Z" } ) ,
127- ] ;
128- expect ( mergeTaskActivity ( previous , incoming ) [ 0 ] . activity_at ) . toBe (
129- "2026-07-05T10:00:00Z" ,
130- ) ;
131- } ) ;
132-
133- it ( "returns the previous page unchanged when there is nothing new" , ( ) => {
134- const previous = [ activity ( { task_id : "t1" } ) ] ;
135- expect ( mergeTaskActivity ( previous , [ ] ) ) . toEqual ( previous ) ;
136- } ) ;
137-
138- it ( "caps the merged result so a long session can't grow it unbounded" , ( ) => {
139- const previous = Array . from ( { length : 300 } , ( _ , i ) =>
140- activity ( {
141- task_id : `old-${ i } ` ,
142- activity_at : `2026-06-01T${ String ( i % 24 ) . padStart ( 2 , "0" ) } :00:00Z` ,
143- } ) ,
144- ) ;
145- const incoming = [
146- activity ( { task_id : "newest" , activity_at : "2026-07-05T10:00:00Z" } ) ,
147- ] ;
148- const merged = mergeTaskActivity ( previous , incoming ) ;
149- expect ( merged ) . toHaveLength ( 300 ) ;
150- expect ( merged [ 0 ] . task_id ) . toBe ( "newest" ) ;
151- } ) ;
152- } ) ;
0 commit comments