1- import { beforeEach , describe , expect , it , vi } from "vitest" ;
1+ import { beforeAll , beforeEach , describe , expect , it , vi } from "vitest" ;
22
3- import { createMockPoll , createMockPollVote } from "../test/mocks/database.mock " ;
3+ import { cleanAllTables , createTestDb } from "../test/create-test-db " ;
44import { PollService } from "./poll.service" ;
55
6- const { mockDb } = vi . hoisted ( ( ) => {
7- const mockDb : any = {
8- select : vi . fn ( ( ) => mockDb ) ,
9- from : vi . fn ( ( ) => mockDb ) ,
10- where : vi . fn ( ( ) => Promise . resolve ( [ ] ) ) ,
11- insert : vi . fn ( ( ) => mockDb ) ,
12- values : vi . fn ( ( ) => mockDb ) ,
13- returning : vi . fn ( ( ) => Promise . resolve ( [ ] ) ) ,
14- } ;
15-
16- return { mockDb } ;
17- } ) ;
6+ let testDb : Awaited < ReturnType < typeof createTestDb > > ;
187
19- vi . mock ( "../database/db" , ( ) => ( { db : mockDb } ) ) ;
8+ vi . mock ( "../database/db" , ( ) => ( {
9+ get db ( ) {
10+ return testDb ;
11+ } ,
12+ } ) ) ;
2013
2114describe ( "Service: PollService" , ( ) => {
22- beforeEach ( ( ) => {
23- // ... reset all mocks before each test ...
24- mockDb . select . mockClear ( ) . mockReturnValue ( mockDb ) ;
25- mockDb . from . mockClear ( ) . mockReturnValue ( mockDb ) ;
26- mockDb . where . mockClear ( ) . mockResolvedValue ( [ ] ) ;
27- mockDb . insert . mockClear ( ) . mockReturnValue ( mockDb ) ;
28- mockDb . values . mockClear ( ) . mockReturnValue ( mockDb ) ;
29- mockDb . returning . mockClear ( ) . mockResolvedValue ( [ ] ) ;
15+ beforeAll ( async ( ) => {
16+ testDb = await createTestDb ( ) ;
17+ } ) ;
18+
19+ beforeEach ( async ( ) => {
20+ await cleanAllTables ( testDb ) ;
3021 } ) ;
3122
3223 describe ( "createPoll" , ( ) => {
@@ -36,21 +27,6 @@ describe("Service: PollService", () => {
3627 } ) ;
3728
3829 it ( "creates a new poll with the provided details" , async ( ) => {
39- // ARRANGE
40- const mockPoll = createMockPoll ( {
41- messageId : "msg123" ,
42- channelId : "ch456" ,
43- creatorId : "user789" ,
44- question : "What's your favorite color?" ,
45- options : JSON . stringify ( [
46- { text : "Red" , votes : [ ] } ,
47- { text : "Blue" , votes : [ ] } ,
48- { text : "Green" , votes : [ ] } ,
49- ] ) ,
50- endTime : null ,
51- } ) ;
52- mockDb . returning . mockResolvedValue ( [ mockPoll ] ) ;
53-
5430 // ACT
5531 const result = await PollService . createPoll (
5632 "msg123" ,
@@ -61,27 +37,22 @@ describe("Service: PollService", () => {
6137 ) ;
6238
6339 // ASSERT
64- expect ( mockDb . insert ) . toHaveBeenCalledWith ( expect . anything ( ) ) ;
65- expect ( mockDb . values ) . toHaveBeenCalledWith ( {
66- messageId : "msg123" ,
67- channelId : "ch456" ,
68- creatorId : "user789" ,
69- question : "What's your favorite color?" ,
70- options : JSON . stringify ( [
71- { text : "Red" , votes : [ ] } ,
72- { text : "Blue" , votes : [ ] } ,
73- { text : "Green" , votes : [ ] } ,
74- ] ) ,
75- endTime : undefined ,
76- } ) ;
77- expect ( result ) . toEqual ( mockPoll ) ;
40+ expect ( result . messageId ) . toEqual ( "msg123" ) ;
41+ expect ( result . channelId ) . toEqual ( "ch456" ) ;
42+ expect ( result . creatorId ) . toEqual ( "user789" ) ;
43+ expect ( result . question ) . toEqual ( "What's your favorite color?" ) ;
44+ expect ( JSON . parse ( result . options ) ) . toEqual ( [
45+ { text : "Red" , votes : [ ] } ,
46+ { text : "Blue" , votes : [ ] } ,
47+ { text : "Green" , votes : [ ] } ,
48+ ] ) ;
49+ expect ( result . endTime ) . toBeNull ( ) ;
50+ expect ( result . id ) . toBeDefined ( ) ;
7851 } ) ;
7952
8053 it ( "creates a poll with an end time when provided" , async ( ) => {
8154 // ARRANGE
8255 const endTime = new Date ( "2024-12-31T23:59:59Z" ) ;
83- const mockPoll = createMockPoll ( { endTime } ) ;
84- mockDb . returning . mockResolvedValue ( [ mockPoll ] ) ;
8556
8657 // ACT
8758 const result = await PollService . createPoll (
@@ -94,11 +65,6 @@ describe("Service: PollService", () => {
9465 ) ;
9566
9667 // ASSERT
97- expect ( mockDb . values ) . toHaveBeenCalledWith (
98- expect . objectContaining ( {
99- endTime,
100- } ) ,
101- ) ;
10268 expect ( result . endTime ) . toEqual ( endTime ) ;
10369 } ) ;
10470 } ) ;
@@ -111,23 +77,17 @@ describe("Service: PollService", () => {
11177
11278 it ( "returns a poll when found" , async ( ) => {
11379 // ARRANGE
114- const mockPoll = createMockPoll ( { messageId : "msg123" } ) ;
115- mockDb . where . mockResolvedValue ( [ mockPoll ] ) ;
80+ await PollService . createPoll ( "msg123" , "ch456" , "user789" , "Question?" , [ "A" , "B" ] ) ;
11681
11782 // ACT
11883 const result = await PollService . getPoll ( "msg123" ) ;
11984
12085 // ASSERT
121- expect ( mockDb . select ) . toHaveBeenCalled ( ) ;
122- expect ( mockDb . from ) . toHaveBeenCalledWith ( expect . anything ( ) ) ;
123- expect ( mockDb . where ) . toHaveBeenCalled ( ) ;
124- expect ( result ) . toEqual ( mockPoll ) ;
86+ expect ( result ) . not . toBeNull ( ) ;
87+ expect ( result ?. messageId ) . toEqual ( "msg123" ) ;
12588 } ) ;
12689
12790 it ( "returns null when poll is not found" , async ( ) => {
128- // ARRANGE
129- mockDb . where . mockResolvedValue ( [ ] ) ;
130-
13191 // ACT
13292 const result = await PollService . getPoll ( "nonexistent" ) ;
13393
@@ -144,50 +104,43 @@ describe("Service: PollService", () => {
144104
145105 it ( "adds a vote when user has not voted" , async ( ) => {
146106 // ARRANGE
147- // ... mock getUserVote to return null ...
148- mockDb . where . mockResolvedValueOnce ( [ ] ) ;
107+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" ] ) ;
149108
150109 // ACT
151- const result = await PollService . addVote ( 1 , "user123" , 0 ) ;
110+ const result = await PollService . addVote ( poll . id , "user123" , 0 ) ;
152111
153112 // ASSERT
154- expect ( mockDb . insert ) . toHaveBeenCalledWith ( expect . anything ( ) ) ;
155- expect ( mockDb . values ) . toHaveBeenCalledWith ( {
156- pollId : 1 ,
157- userId : "user123" ,
158- optionIndex : 0 ,
159- } ) ;
160113 expect ( result ) . toEqual ( true ) ;
114+
115+ const vote = await PollService . getUserVote ( poll . id , "user123" ) ;
116+ expect ( vote ) . not . toBeNull ( ) ;
117+ expect ( vote ?. optionIndex ) . toEqual ( 0 ) ;
161118 } ) ;
162119
163120 it ( "returns false when user has already voted" , async ( ) => {
164121 // ARRANGE
165- const existingVote = createMockPollVote ( ) ;
166- // ... mock getUserVote to return existing vote ...
167- mockDb . where . mockResolvedValueOnce ( [ existingVote ] ) ;
122+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" ] ) ;
123+ await PollService . addVote ( poll . id , "user123" , 0 ) ;
168124
169125 // ACT
170- const result = await PollService . addVote ( 1 , "user123" , 1 ) ;
126+ const result = await PollService . addVote ( poll . id , "user123" , 1 ) ;
171127
172128 // ASSERT
173- expect ( mockDb . insert ) . not . toHaveBeenCalled ( ) ;
174129 expect ( result ) . toEqual ( false ) ;
175130 } ) ;
176131
177132 it ( "allows voting for different option indices" , async ( ) => {
178133 // ARRANGE
179- mockDb . where . mockResolvedValueOnce ( [ ] ) ; // ... no existing vote ...
134+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" , "C" ] ) ;
180135
181136 // ACT
182- const result = await PollService . addVote ( 1 , "user123" , 2 ) ;
137+ const result = await PollService . addVote ( poll . id , "user123" , 2 ) ;
183138
184139 // ASSERT
185- expect ( mockDb . values ) . toHaveBeenCalledWith ( {
186- pollId : 1 ,
187- userId : "user123" ,
188- optionIndex : 2 ,
189- } ) ;
190140 expect ( result ) . toEqual ( true ) ;
141+
142+ const vote = await PollService . getUserVote ( poll . id , "user123" ) ;
143+ expect ( vote ?. optionIndex ) . toEqual ( 2 ) ;
191144 } ) ;
192145 } ) ;
193146
@@ -199,29 +152,25 @@ describe("Service: PollService", () => {
199152
200153 it ( "returns a vote when user has voted" , async ( ) => {
201154 // ARRANGE
202- const mockVote = createMockPollVote ( {
203- pollId : 1 ,
204- userId : "user123" ,
205- optionIndex : 1 ,
206- } ) ;
207- mockDb . where . mockResolvedValue ( [ mockVote ] ) ;
155+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" ] ) ;
156+ await PollService . addVote ( poll . id , "user123" , 1 ) ;
208157
209158 // ACT
210- const result = await PollService . getUserVote ( 1 , "user123" ) ;
159+ const result = await PollService . getUserVote ( poll . id , "user123" ) ;
211160
212161 // ASSERT
213- expect ( mockDb . select ) . toHaveBeenCalled ( ) ;
214- expect ( mockDb . from ) . toHaveBeenCalledWith ( expect . anything ( ) ) ;
215- expect ( mockDb . where ) . toHaveBeenCalled ( ) ;
216- expect ( result ) . toEqual ( mockVote ) ;
162+ expect ( result ) . not . toBeNull ( ) ;
163+ expect ( result ?. pollId ) . toEqual ( poll . id ) ;
164+ expect ( result ?. userId ) . toEqual ( "user123" ) ;
165+ expect ( result ?. optionIndex ) . toEqual ( 1 ) ;
217166 } ) ;
218167
219168 it ( "returns null when user has not voted" , async ( ) => {
220169 // ARRANGE
221- mockDb . where . mockResolvedValue ( [ ] ) ;
170+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" ] ) ;
222171
223172 // ACT
224- const result = await PollService . getUserVote ( 1 , "user456" ) ;
173+ const result = await PollService . getUserVote ( poll . id , "user456" ) ;
225174
226175 // ASSERT
227176 expect ( result ) . toBeNull ( ) ;
@@ -236,17 +185,15 @@ describe("Service: PollService", () => {
236185
237186 it ( "returns vote counts by option index" , async ( ) => {
238187 // ARRANGE
239- const mockVotes = [
240- createMockPollVote ( { optionIndex : 0 } ) ,
241- createMockPollVote ( { optionIndex : 0 } ) ,
242- createMockPollVote ( { optionIndex : 1 } ) ,
243- createMockPollVote ( { optionIndex : 0 } ) ,
244- createMockPollVote ( { optionIndex : 2 } ) ,
245- ] ;
246- mockDb . where . mockResolvedValue ( mockVotes ) ;
188+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" , "C" ] ) ;
189+ await PollService . addVote ( poll . id , "user1" , 0 ) ;
190+ await PollService . addVote ( poll . id , "user2" , 0 ) ;
191+ await PollService . addVote ( poll . id , "user3" , 1 ) ;
192+ await PollService . addVote ( poll . id , "user4" , 0 ) ;
193+ await PollService . addVote ( poll . id , "user5" , 2 ) ;
247194
248195 // ACT
249- const results = await PollService . getPollResults ( 1 ) ;
196+ const results = await PollService . getPollResults ( poll . id ) ;
250197
251198 // ASSERT
252199 expect ( results ) . toBeInstanceOf ( Map ) ;
@@ -257,26 +204,31 @@ describe("Service: PollService", () => {
257204
258205 it ( "returns empty map when there are no votes" , async ( ) => {
259206 // ARRANGE
260- mockDb . where . mockResolvedValue ( [ ] ) ;
207+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" ] ) ;
261208
262209 // ACT
263- const results = await PollService . getPollResults ( 1 ) ;
210+ const results = await PollService . getPollResults ( poll . id ) ;
264211
265212 // ASSERT
266213 expect ( results . size ) . toEqual ( 0 ) ;
267214 } ) ;
268215
269216 it ( "handles votes for non-sequential option indices" , async ( ) => {
270217 // ARRANGE
271- const mockVotes = [
272- createMockPollVote ( { optionIndex : 0 } ) ,
273- createMockPollVote ( { optionIndex : 5 } ) ,
274- createMockPollVote ( { optionIndex : 5 } ) ,
275- ] ;
276- mockDb . where . mockResolvedValue ( mockVotes ) ;
218+ const poll = await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [
219+ "A" ,
220+ "B" ,
221+ "C" ,
222+ "D" ,
223+ "E" ,
224+ "F" ,
225+ ] ) ;
226+ await PollService . addVote ( poll . id , "user1" , 0 ) ;
227+ await PollService . addVote ( poll . id , "user2" , 5 ) ;
228+ await PollService . addVote ( poll . id , "user3" , 5 ) ;
277229
278230 // ACT
279- const results = await PollService . getPollResults ( 1 ) ;
231+ const results = await PollService . getPollResults ( poll . id ) ;
280232
281233 // ASSERT
282234 expect ( results . get ( 0 ) ) . toEqual ( 1 ) ;
@@ -293,25 +245,20 @@ describe("Service: PollService", () => {
293245
294246 it ( "returns polls with no end time" , async ( ) => {
295247 // ARRANGE
296- const mockPolls = [
297- createMockPoll ( { id : 1 , endTime : null } ) ,
298- createMockPoll ( { id : 2 , endTime : null } ) ,
299- ] ;
300- mockDb . where . mockResolvedValue ( mockPolls ) ;
248+ await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q1?" , [ "A" , "B" ] ) ;
249+ await PollService . createPoll ( "msg2" , "ch1" , "creator1" , "Q2?" , [ "A" , "B" ] ) ;
250+ await PollService . createPoll ( "msg3" , "ch1" , "creator1" , "Q3?" , [ "A" , "B" ] , new Date ( ) ) ;
301251
302252 // ACT
303253 const result = await PollService . getActivePolls ( ) ;
304254
305255 // ASSERT
306- expect ( mockDb . select ) . toHaveBeenCalled ( ) ;
307- expect ( mockDb . from ) . toHaveBeenCalledWith ( expect . anything ( ) ) ;
308- expect ( mockDb . where ) . toHaveBeenCalled ( ) ;
309- expect ( result ) . toEqual ( mockPolls ) ;
256+ expect ( result ) . toHaveLength ( 2 ) ;
310257 } ) ;
311258
312259 it ( "returns empty array when there are no active polls" , async ( ) => {
313260 // ARRANGE
314- mockDb . where . mockResolvedValue ( [ ] ) ;
261+ await PollService . createPoll ( "msg1" , "ch1" , "creator1" , "Q?" , [ "A" , "B" ] , new Date ( ) ) ;
315262
316263 // ACT
317264 const result = await PollService . getActivePolls ( ) ;
0 commit comments