Skip to content

Commit b2ba8c8

Browse files
Merge pull request #788 from decentraland/fix/re-discovery-fix-live-property
feat: implement batch checking for live events in Events API
2 parents ec115a3 + 841cbaf commit b2ba8c8

File tree

4 files changed

+199
-126
lines changed

4 files changed

+199
-126
lines changed

src/api/Events.test.ts

Lines changed: 120 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,83 @@ import Events from "./Events"
33
describe("Events API", () => {
44
let fetchMock: jest.SpyInstance
55

6+
beforeEach(() => {
7+
// Clear both caches before each test
8+
;(Events as any).Cache.clear()
9+
;(Events as any).liveEventCache.clear()
10+
})
11+
612
afterEach(() => {
713
fetchMock?.mockRestore()
814
jest.clearAllMocks()
9-
// Clear cache between tests
10-
;(Events as any).liveEventCache.clear()
1115
})
1216

13-
describe("when checking if a destination has a live event", () => {
14-
describe("and the API returns live events", () => {
15-
let result: boolean
17+
describe("when checking live events for multiple destinations", () => {
18+
describe("and the API returns live events for some destinations", () => {
19+
let result: Map<string, boolean>
1620

1721
beforeEach(async () => {
1822
fetchMock = jest.spyOn(Events.get(), "fetch").mockResolvedValueOnce({
1923
ok: true,
20-
data: [{ id: "event-1", live: true }],
24+
data: {
25+
events: [
26+
{ id: "event-1", place_id: "place-1", live: true },
27+
{ id: "event-world", place_id: "world-id", live: true },
28+
],
29+
total: 2,
30+
},
2131
})
2232

23-
result = await Events.get().hasLiveEvent("destination-123")
33+
result = await Events.get().checkLiveEventsForDestinations([
34+
"place-1",
35+
"place-2",
36+
"world-id",
37+
])
38+
})
39+
40+
it("should return true for destinations with live events", () => {
41+
expect(result.get("place-1")).toBe(true)
42+
expect(result.get("world-id")).toBe(true)
2443
})
2544

26-
it("should return true", () => {
27-
expect(result).toBe(true)
45+
it("should return false for destinations without live events", () => {
46+
expect(result.get("place-2")).toBe(false)
2847
})
2948

30-
it("should call the events API with correct parameters", () => {
49+
it("should call the events API with list=live query param", () => {
3150
expect(fetchMock).toHaveBeenCalledWith(
32-
"/events?places_ids=destination-123&list=live",
51+
"/events?list=live",
3352
expect.anything()
3453
)
3554
})
3655
})
3756

3857
describe("and the API returns no live events", () => {
39-
let result: boolean
58+
let result: Map<string, boolean>
4059

4160
beforeEach(async () => {
4261
fetchMock = jest.spyOn(Events.get(), "fetch").mockResolvedValueOnce({
4362
ok: true,
44-
data: [],
63+
data: {
64+
events: [],
65+
total: 0,
66+
},
4567
})
4668

47-
result = await Events.get().hasLiveEvent("destination-456")
69+
result = await Events.get().checkLiveEventsForDestinations([
70+
"place-1",
71+
"place-2",
72+
])
4873
})
4974

50-
it("should return false", () => {
51-
expect(result).toBe(false)
75+
it("should return false for all destinations", () => {
76+
expect(result.get("place-1")).toBe(false)
77+
expect(result.get("place-2")).toBe(false)
5278
})
5379
})
5480

5581
describe("and the API call fails", () => {
56-
let result: boolean
82+
let result: Map<string, boolean>
5783
let consoleErrorSpy: jest.SpyInstance
5884

5985
beforeEach(async () => {
@@ -62,20 +88,24 @@ describe("Events API", () => {
6288
.spyOn(Events.get(), "fetch")
6389
.mockRejectedValueOnce(new Error("Network error"))
6490

65-
result = await Events.get().hasLiveEvent("destination-error")
91+
result = await Events.get().checkLiveEventsForDestinations([
92+
"place-1",
93+
"place-2",
94+
])
6695
})
6796

6897
afterEach(() => {
6998
consoleErrorSpy.mockRestore()
7099
})
71100

72-
it("should return false", () => {
73-
expect(result).toBe(false)
101+
it("should return false for all destinations", () => {
102+
expect(result.get("place-1")).toBe(false)
103+
expect(result.get("place-2")).toBe(false)
74104
})
75105

76106
it("should log the error", () => {
77107
expect(consoleErrorSpy).toHaveBeenCalledWith(
78-
"Error checking live events for destination destination-error:",
108+
"Error checking live events for destinations:",
79109
expect.any(Error)
80110
)
81111
})
@@ -85,58 +115,91 @@ describe("Events API", () => {
85115
beforeEach(async () => {
86116
fetchMock = jest.spyOn(Events.get(), "fetch").mockResolvedValueOnce({
87117
ok: true,
88-
data: [{ id: "event-1", live: true }],
118+
data: {
119+
events: [{ id: "event-1", place_id: "place-1", live: true }],
120+
total: 1,
121+
},
89122
})
90123

91124
// First call - should fetch
92-
await Events.get().hasLiveEvent("destination-cached")
125+
await Events.get().checkLiveEventsForDestinations([
126+
"place-1",
127+
"place-2",
128+
])
93129
// Second call - should use cache
94-
await Events.get().hasLiveEvent("destination-cached")
130+
await Events.get().checkLiveEventsForDestinations([
131+
"place-1",
132+
"place-2",
133+
])
95134
})
96135

97136
it("should only call the API once", () => {
98137
expect(fetchMock).toHaveBeenCalledTimes(1)
99138
})
100139
})
101-
})
102140

103-
describe("when checking live events for multiple destinations", () => {
104-
let result: Map<string, boolean>
141+
describe("and requesting new IDs alongside cached IDs", () => {
142+
let result: Map<string, boolean>
105143

106-
beforeEach(async () => {
107-
fetchMock = jest
108-
.spyOn(Events.get(), "fetch")
109-
// First call for place-1
110-
.mockResolvedValueOnce({
111-
ok: true,
112-
data: [{ id: "event-1", live: true }],
113-
})
114-
// Second call for place-2
115-
.mockResolvedValueOnce({
116-
ok: true,
117-
data: [],
118-
})
119-
// Third call for world-id
120-
.mockResolvedValueOnce({
121-
ok: true,
122-
data: [{ id: "event-world", live: true }],
123-
})
144+
beforeEach(async () => {
145+
fetchMock = jest
146+
.spyOn(Events.get(), "fetch")
147+
// First call for place-1, place-2
148+
.mockResolvedValueOnce({
149+
ok: true,
150+
data: {
151+
events: [{ id: "event-1", place_id: "place-1", live: true }],
152+
total: 1,
153+
},
154+
})
155+
// Second call for only place-3 (place-1 and place-2 are cached)
156+
.mockResolvedValueOnce({
157+
ok: true,
158+
data: {
159+
events: [{ id: "event-3", place_id: "place-3", live: true }],
160+
total: 1,
161+
},
162+
})
163+
164+
// First call - fetch place-1, place-2
165+
await Events.get().checkLiveEventsForDestinations([
166+
"place-1",
167+
"place-2",
168+
])
169+
// Second call - place-1 and place-2 are cached, only fetch place-3
170+
result = await Events.get().checkLiveEventsForDestinations([
171+
"place-1",
172+
"place-2",
173+
"place-3",
174+
])
175+
})
124176

125-
result = await Events.get().checkLiveEventsForDestinations([
126-
"place-1",
127-
"place-2",
128-
"world-id",
129-
])
130-
})
177+
it("should only fetch uncached IDs", () => {
178+
expect(fetchMock).toHaveBeenCalledTimes(2)
179+
})
131180

132-
it("should return a map with live status for each destination", () => {
133-
expect(result.get("place-1")).toBe(true)
134-
expect(result.get("place-2")).toBe(false)
135-
expect(result.get("world-id")).toBe(true)
181+
it("should return correct live status for all IDs", () => {
182+
expect(result.get("place-1")).toBe(true) // from cache
183+
expect(result.get("place-2")).toBe(false) // from cache
184+
expect(result.get("place-3")).toBe(true) // freshly fetched
185+
})
136186
})
137187

138-
it("should call the API for each destination", () => {
139-
expect(fetchMock).toHaveBeenCalledTimes(3)
188+
describe("and an empty array is passed", () => {
189+
let result: Map<string, boolean>
190+
191+
beforeEach(async () => {
192+
fetchMock = jest.spyOn(Events.get(), "fetch")
193+
result = await Events.get().checkLiveEventsForDestinations([])
194+
})
195+
196+
it("should return an empty map", () => {
197+
expect(result.size).toBe(0)
198+
})
199+
200+
it("should not call the API", () => {
201+
expect(fetchMock).not.toHaveBeenCalled()
202+
})
140203
})
141204
})
142205
})

0 commit comments

Comments
 (0)