hubot-nextbus 2.2.2 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
1
  {
2
- "total": 95,
2
+ "total": 46,
3
3
  "page": 1,
4
4
  "per_page": 5,
5
5
  "data": [
6
6
  {
7
- "id": 204,
8
- "stop_gid": "CHA7AWN",
9
- "stop_code": "CHA7AWN",
10
- "stop_name": "CHARLOTTE AVE & 7TH AVE N WB",
11
- "stop_desc": null,
12
- "stop_lat": "36.165",
13
- "stop_lon": "-86.78406",
7
+ "id": 288382,
8
+ "stop_gid": "BRO12WN",
9
+ "stop_code": "489",
10
+ "stop_name": "BROADWAY AVE \u0026 12TH AVE N WB",
11
+ "stop_desc": "103 12TH AVE \u0026 BROADWAY AVE",
12
+ "stop_lat": "36.156751",
13
+ "stop_lon": "-86.787397",
14
14
  "zone_gid": null,
15
15
  "stop_url": null,
16
16
  "location_type": null,
@@ -18,35 +18,35 @@
18
18
  "parent_station_id": null,
19
19
  "stop_timezone": null,
20
20
  "wheelchair_boarding": "0",
21
- "created_at": "2022-08-02T21:14:07.970-05:00",
22
- "updated_at": "2022-08-02T21:14:07.970-05:00"
21
+ "created_at": "2026-08-30T04:05:14.980-05:00",
22
+ "updated_at": "2026-08-30T04:05:14.980-05:00"
23
23
  },
24
24
  {
25
- "id": 203,
26
- "stop_gid": "CHA7AEN",
27
- "stop_code": "CHA7AEN",
28
- "stop_name": "CHARLOTTE AVE & 7TH AVE N EB",
29
- "stop_desc": null,
30
- "stop_lat": "36.164714",
31
- "stop_lon": "-86.784416",
32
- "zone_gid": null,
25
+ "id": 289285,
26
+ "stop_gid": "BRO12AEF",
27
+ "stop_code": "4588",
28
+ "stop_name": "BROADWAY AVE \u0026 12TH AVE EB",
29
+ "stop_desc": "1232 BROADWAY AVE \u0026 12TH AVE",
30
+ "stop_lat": "36.15665",
31
+ "stop_lon": "-86.787086",
32
+ "zone_gid": "0",
33
33
  "stop_url": null,
34
34
  "location_type": null,
35
35
  "parent_station_gid": null,
36
36
  "parent_station_id": null,
37
37
  "stop_timezone": null,
38
38
  "wheelchair_boarding": "0",
39
- "created_at": "2022-08-02T21:14:07.970-05:00",
40
- "updated_at": "2022-08-02T21:14:07.970-05:00"
39
+ "created_at": "2026-08-30T04:05:15.505-05:00",
40
+ "updated_at": "2026-08-30T04:05:15.505-05:00"
41
41
  },
42
42
  {
43
- "id": 1136,
44
- "stop_gid": "6AVDEASN",
45
- "stop_code": "6AVDEASN",
46
- "stop_name": "6TH AVE & DEADERICK ST SB",
47
- "stop_desc": "6TH AVE N & UNION ST",
48
- "stop_lat": "36.16483",
49
- "stop_lon": "-86.782945",
43
+ "id": 289485,
44
+ "stop_gid": "11APORSF",
45
+ "stop_code": "5275",
46
+ "stop_name": "11TH AVE \u0026 PORTER ST SB",
47
+ "stop_desc": "303 11TH AVE \u0026 PORTER ST",
48
+ "stop_lat": "36.157903",
49
+ "stop_lon": "-86.786781",
50
50
  "zone_gid": null,
51
51
  "stop_url": null,
52
52
  "location_type": null,
@@ -54,44 +54,44 @@
54
54
  "parent_station_id": null,
55
55
  "stop_timezone": null,
56
56
  "wheelchair_boarding": null,
57
- "created_at": "2022-08-02T21:14:08.168-05:00",
58
- "updated_at": "2022-08-02T21:14:08.168-05:00"
57
+ "created_at": "2026-08-30T04:05:15.505-05:00",
58
+ "updated_at": "2026-08-30T04:05:15.505-05:00"
59
59
  },
60
60
  {
61
- "id": 838,
62
- "stop_gid": "6AVDEANN",
63
- "stop_code": "6AVDEANN",
64
- "stop_name": "6TH AVE N & DEADERICK ST NB",
65
- "stop_desc": "6TH AV N & DEADERICK ST",
66
- "stop_lat": "36.16466",
67
- "stop_lon": "-86.782651",
61
+ "id": 289490,
62
+ "stop_gid": "11APORNN",
63
+ "stop_code": "5281",
64
+ "stop_name": "11TH AVE \u0026 PORTER ST NB",
65
+ "stop_desc": "302 11TH AVE \u0026 PORTER ST",
66
+ "stop_lat": "36.157887",
67
+ "stop_lon": "-86.786591",
68
68
  "zone_gid": null,
69
69
  "stop_url": null,
70
70
  "location_type": null,
71
71
  "parent_station_gid": null,
72
72
  "parent_station_id": null,
73
73
  "stop_timezone": null,
74
- "wheelchair_boarding": "0",
75
- "created_at": "2022-08-02T21:14:08.075-05:00",
76
- "updated_at": "2022-08-02T21:14:08.075-05:00"
74
+ "wheelchair_boarding": null,
75
+ "created_at": "2026-08-30T04:05:15.505-05:00",
76
+ "updated_at": "2026-08-30T04:05:15.505-05:00"
77
77
  },
78
78
  {
79
- "id": 722,
80
- "stop_gid": "UNI7AWN",
81
- "stop_code": "UNI7AWN",
82
- "stop_name": "UNION ST & 7TH AVE N WB",
83
- "stop_desc": "UNION & 7 AVE",
84
- "stop_lat": "36.163599",
85
- "stop_lon": "-86.783404",
86
- "zone_gid": null,
79
+ "id": 289337,
80
+ "stop_gid": "BRO10AEN",
81
+ "stop_code": "4825",
82
+ "stop_name": "BROADWAY \u0026 10TH AVE EB",
83
+ "stop_desc": "937 ",
84
+ "stop_lat": "36.157678",
85
+ "stop_lon": "-86.78468",
86
+ "zone_gid": "0",
87
87
  "stop_url": null,
88
- "location_type": null,
88
+ "location_type": "0",
89
89
  "parent_station_gid": null,
90
90
  "parent_station_id": null,
91
91
  "stop_timezone": null,
92
- "wheelchair_boarding": null,
93
- "created_at": "2022-08-02T21:14:08.075-05:00",
94
- "updated_at": "2022-08-02T21:14:08.075-05:00"
92
+ "wheelchair_boarding": "0",
93
+ "created_at": "2026-08-30T04:05:15.505-05:00",
94
+ "updated_at": "2026-08-30T04:05:15.505-05:00"
95
95
  }
96
96
  ]
97
97
  }
@@ -0,0 +1,77 @@
1
+ const path = require('path');
2
+
3
+ class Helper {
4
+ constructor(scriptPaths) {
5
+ this.scriptPaths = Array.isArray(scriptPaths) ? scriptPaths : [scriptPaths];
6
+ }
7
+
8
+ async createRoom(options = {}) {
9
+ const {
10
+ Robot, User, TextMessage, EnterMessage, LeaveMessage,
11
+ } = await import('hubot');
12
+
13
+ const messages = [];
14
+ const roomName = options.name || 'room1';
15
+
16
+ const adapter = {
17
+ name: 'mock',
18
+ messages,
19
+ send: async (_envelope, ...strings) => {
20
+ strings.forEach((str) => messages.push(['hubot', str]));
21
+ },
22
+ reply: async (envelope, ...strings) => {
23
+ strings.forEach((str) => messages.push(['hubot', `@${envelope.user.name} ${str}`]));
24
+ },
25
+ run: async () => {},
26
+ };
27
+
28
+ const robot = new Robot(adapter, false, 'hubot');
29
+
30
+ await this.scriptPaths.reduce(async (previous, scriptPath) => {
31
+ await previous;
32
+ const resolved = path.resolve(process.cwd(), scriptPath);
33
+ await robot.loadFile(path.dirname(resolved), path.basename(resolved));
34
+ }, Promise.resolve());
35
+
36
+ robot.brain.emit('loaded');
37
+
38
+ return {
39
+ robot,
40
+ messages,
41
+ name: roomName,
42
+ user: {
43
+ say: async (userName, message, userParams = {}) => {
44
+ userParams.room = roomName;
45
+ const user = new User(userName, userParams);
46
+ const textMessage = new TextMessage(user, message);
47
+ messages.push([userName, textMessage.text]);
48
+ await robot.receive(textMessage);
49
+ },
50
+ enter: async (userName, userParams = {}) => {
51
+ userParams.room = roomName;
52
+ const user = new User(userName, userParams);
53
+ await robot.receive(new EnterMessage(user));
54
+ },
55
+ leave: async (userName, userParams = {}) => {
56
+ userParams.room = roomName;
57
+ const user = new User(userName, userParams);
58
+ await robot.receive(new LeaveMessage(user));
59
+ },
60
+ },
61
+ destroy: () => {
62
+ if (robot.server) robot.server.close();
63
+ robot.brain.close();
64
+ },
65
+ waitForMessages: async (count, timeout = 2000) => {
66
+ const start = Date.now();
67
+ while (messages.length < count) {
68
+ if (Date.now() - start > timeout) break;
69
+ // eslint-disable-next-line no-await-in-loop
70
+ await new Promise((resolve) => { setTimeout(resolve, 10); });
71
+ }
72
+ },
73
+ };
74
+ }
75
+ }
76
+
77
+ module.exports = Helper;
@@ -0,0 +1,132 @@
1
+ /* global describe beforeEach afterEach it expect */
2
+
3
+ const nock = require('nock');
4
+ const Helper = require('./helpers/hubot-helper');
5
+
6
+ const helper = new Helper([
7
+ './test/adapters/slack.js',
8
+ './src/nextbus.js',
9
+ ]);
10
+
11
+ // Alter time as test runs
12
+ const originalDateNow = Date.now;
13
+
14
+ const tripTableBlocks = (heading, rows) => ({
15
+ blocks: [
16
+ {
17
+ type: 'header',
18
+ text: { type: 'plain_text', text: heading, emoji: true },
19
+ },
20
+ {
21
+ type: 'table',
22
+ rows: [['Time', 'Route', 'ETA'], ...rows].map((row) => row.map((cell) => ({
23
+ type: 'raw_text',
24
+ text: cell,
25
+ }))),
26
+ },
27
+ ],
28
+ });
29
+
30
+ describe('hubot-nextbus for slack', () => {
31
+ let room = null;
32
+
33
+ beforeEach(() => {
34
+ nock.disableNetConnect();
35
+ nock('https://gtfs.transitnownash.org')
36
+ .get('/stops/near/36.156751,-86.787397/1000.json?per_page=5')
37
+ .replyWithFile(200, `${__dirname}/fixtures/stops-near-gps.json`);
38
+ nock('https://gtfs.transitnownash.org')
39
+ .get('/agencies.json')
40
+ .replyWithFile(200, `${__dirname}/fixtures/agencies.json`);
41
+ nock('https://gtfs.transitnownash.org')
42
+ .get('/stops/BRO12WN/next.json')
43
+ .replyWithFile(200, `${__dirname}/fixtures/stops-BRO12WN-next.json`);
44
+ nock('https://gtfs.transitnownash.org')
45
+ .get('/stops/489/next.json')
46
+ .replyWithFile(200, `${__dirname}/fixtures/stops-BRO12WN-next.json`);
47
+ });
48
+
49
+ afterEach(() => {
50
+ nock.cleanAll();
51
+ Date.now = originalDateNow;
52
+ });
53
+
54
+ describe('regular tests with latitude/longitude set', () => {
55
+ beforeEach(async () => {
56
+ Date.now = () => Date.parse('Sun Aug 30 2026 12:58:00 GMT-0500 (Central Daylight Time)');
57
+ process.env.HUBOT_NEXTBUS_LAT_LON = '36.156751,-86.787397';
58
+ room = await helper.createRoom();
59
+ });
60
+
61
+ afterEach(() => {
62
+ room.destroy();
63
+ delete process.env.HUBOT_NEXTBUS_LAT_LON;
64
+ });
65
+
66
+ // hubot nextbus
67
+ it('returns the next bus for closest stop', async () => {
68
+ await room.user.say('alice', '@hubot nextbus');
69
+ await room.waitForMessages(3);
70
+ expect(room.messages).toEqual([
71
+ ['alice', '@hubot nextbus'],
72
+ [
73
+ 'hubot',
74
+ '⚠️ *6TH AVE & DEADERICK ST SB is not currently being served due to Construction.*\n'
75
+ + '⚠️ *Detour in effect on route 7 HILLSBORO TO DOWNTOWN*\n'
76
+ + '⚠️ *Detour in effect on route 7 HILLSBORO FROM DOWNTOWN*',
77
+ ],
78
+ [
79
+ 'hubot',
80
+ tripTableBlocks('🚏 BROADWAY AVE & 12TH AVE N WB', [
81
+ ['1:01 PM', '#7 - GREEN HILLS 🚌', 'in 4 minutes (On time)'],
82
+ ['1:06 PM', '#3 - B - BELLEVUE 🚌', 'in 9 minutes (On time)'],
83
+ ['1:21 PM', '#3 - A -WHITE BRIDGE', 'in 24 minutes (On time)'],
84
+ ['1:21 PM', '#7 - GREEN HILLS', 'in 24 minutes (On time)'],
85
+ ]),
86
+ ],
87
+ ]);
88
+ });
89
+
90
+ // hubot nextbus stop <id>
91
+ it('returns the next bus for a particular stop', async () => {
92
+ await room.user.say('alice', '@hubot nextbus stop BRO12WN');
93
+ await room.waitForMessages(3);
94
+ expect(room.messages).toEqual([
95
+ ['alice', '@hubot nextbus stop BRO12WN'],
96
+ [
97
+ 'hubot',
98
+ '⚠️ *6TH AVE & DEADERICK ST SB is not currently being served due to Construction.*\n'
99
+ + '⚠️ *Detour in effect on route 7 HILLSBORO TO DOWNTOWN*\n'
100
+ + '⚠️ *Detour in effect on route 7 HILLSBORO FROM DOWNTOWN*',
101
+ ],
102
+ [
103
+ 'hubot',
104
+ tripTableBlocks('🚏 BROADWAY AVE & 12TH AVE N WB', [
105
+ ['1:01 PM', '#7 - GREEN HILLS 🚌', 'in 4 minutes (On time)'],
106
+ ['1:06 PM', '#3 - B - BELLEVUE 🚌', 'in 9 minutes (On time)'],
107
+ ['1:21 PM', '#3 - A -WHITE BRIDGE', 'in 24 minutes (On time)'],
108
+ ['1:21 PM', '#7 - GREEN HILLS', 'in 24 minutes (On time)'],
109
+ ]),
110
+ ],
111
+ ]);
112
+ });
113
+
114
+ // hubot nextbus stops
115
+ it('returns the list of nearby stops', async () => {
116
+ await room.user.say('alice', '@hubot nextbus stops');
117
+ await room.waitForMessages(3);
118
+ expect(room.messages).toEqual([
119
+ ['alice', '@hubot nextbus stops'],
120
+ ['hubot', 'List of nearby stops:'],
121
+ [
122
+ 'hubot',
123
+ '- `#489` - BROADWAY AVE & 12TH AVE N WB\n'
124
+ + '- `#4588` - BROADWAY AVE & 12TH AVE EB\n'
125
+ + '- `#5275` - 11TH AVE & PORTER ST SB\n'
126
+ + '- `#5281` - 11TH AVE & PORTER ST NB\n'
127
+ + '- `#4825` - BROADWAY & 10TH AVE EB',
128
+ ],
129
+ ]);
130
+ });
131
+ });
132
+ });
@@ -0,0 +1,178 @@
1
+ /* global describe beforeEach afterEach it expect */
2
+
3
+ const nock = require('nock');
4
+ const Helper = require('./helpers/hubot-helper');
5
+
6
+ const helper = new Helper('./src/nextbus.js');
7
+
8
+ // Alter time as test runs
9
+ const originalDateNow = Date.now;
10
+
11
+ describe('hubot-nextbus', () => {
12
+ let room = null;
13
+
14
+ beforeEach(() => {
15
+ nock.disableNetConnect();
16
+ nock('https://gtfs.transitnownash.org')
17
+ .get('/stops/near/36.156751,-86.787397/1000.json?per_page=5')
18
+ .replyWithFile(200, `${__dirname}/fixtures/stops-near-gps.json`);
19
+ nock('https://gtfs.transitnownash.org')
20
+ .get('/agencies.json')
21
+ .replyWithFile(200, `${__dirname}/fixtures/agencies.json`);
22
+ nock('https://gtfs.transitnownash.org')
23
+ .get('/stops/BRO12WN/next.json')
24
+ .replyWithFile(200, `${__dirname}/fixtures/stops-BRO12WN-next.json`);
25
+ nock('https://gtfs.transitnownash.org')
26
+ .get('/stops/489/next.json')
27
+ .replyWithFile(200, `${__dirname}/fixtures/stops-BRO12WN-next.json`);
28
+ nock('https://gtfs.transitnownash.org')
29
+ .get('/stops/PORGRESF/next.json')
30
+ .replyWithFile(200, `${__dirname}/fixtures/stops-PORGRESF-next.json`);
31
+ });
32
+
33
+ afterEach(() => {
34
+ nock.cleanAll();
35
+ Date.now = originalDateNow;
36
+ });
37
+
38
+ describe('regular tests with latitude/longitude set', () => {
39
+ beforeEach(async () => {
40
+ Date.now = () => Date.parse('Sun Aug 30 2026 12:58:00 GMT-0500 (Central Daylight Time)');
41
+ process.env.HUBOT_NEXTBUS_LAT_LON = '36.156751,-86.787397';
42
+ room = await helper.createRoom();
43
+ });
44
+
45
+ afterEach(() => {
46
+ room.destroy();
47
+ delete process.env.HUBOT_NEXTBUS_LAT_LON;
48
+ });
49
+
50
+ // hubot nextbus
51
+ it('returns the next bus for closest stop', async () => {
52
+ await room.user.say('alice', '@hubot nextbus');
53
+ await room.waitForMessages(3);
54
+ expect(room.messages).toEqual([
55
+ ['alice', '@hubot nextbus'],
56
+ [
57
+ 'hubot',
58
+ '⚠️ *6TH AVE & DEADERICK ST SB is not currently being served due to Construction.*\n'
59
+ + '⚠️ *Detour in effect on route 7 HILLSBORO TO DOWNTOWN*\n'
60
+ + '⚠️ *Detour in effect on route 7 HILLSBORO FROM DOWNTOWN*',
61
+ ],
62
+ [
63
+ 'hubot',
64
+ '🚏 *BROADWAY AVE & 12TH AVE N WB*\n'
65
+ + ' 1:01 PM #7 - GREEN HILLS 🚌 in 4 minutes (On time)\n'
66
+ + ' 1:06 PM #3 - B - BELLEVUE 🚌 in 9 minutes (On time)\n'
67
+ + ' 1:21 PM #3 - A -WHITE BRIDGE in 24 minutes (On time)\n'
68
+ + ' 1:21 PM #7 - GREEN HILLS in 24 minutes (On time)',
69
+ ],
70
+ ]);
71
+ });
72
+
73
+ // hubot nextbus stop <id>
74
+ it('returns the next bus for a particular stop', async () => {
75
+ await room.user.say('alice', '@hubot nextbus stop BRO12WN');
76
+ await room.waitForMessages(3);
77
+ expect(room.messages).toEqual([
78
+ ['alice', '@hubot nextbus stop BRO12WN'],
79
+ [
80
+ 'hubot',
81
+ '⚠️ *6TH AVE & DEADERICK ST SB is not currently being served due to Construction.*\n'
82
+ + '⚠️ *Detour in effect on route 7 HILLSBORO TO DOWNTOWN*\n'
83
+ + '⚠️ *Detour in effect on route 7 HILLSBORO FROM DOWNTOWN*',
84
+ ],
85
+ [
86
+ 'hubot',
87
+ '🚏 *BROADWAY AVE & 12TH AVE N WB*\n'
88
+ + ' 1:01 PM #7 - GREEN HILLS 🚌 in 4 minutes (On time)\n'
89
+ + ' 1:06 PM #3 - B - BELLEVUE 🚌 in 9 minutes (On time)\n'
90
+ + ' 1:21 PM #3 - A -WHITE BRIDGE in 24 minutes (On time)\n'
91
+ + ' 1:21 PM #7 - GREEN HILLS in 24 minutes (On time)',
92
+ ],
93
+ ]);
94
+ });
95
+
96
+ // hubot nextbus stops
97
+ it('returns the list of nearby stops', async () => {
98
+ await room.user.say('alice', '@hubot nextbus stops');
99
+ await room.waitForMessages(3);
100
+ expect(room.messages).toEqual([
101
+ ['alice', '@hubot nextbus stops'],
102
+ ['hubot', 'List of nearby stops:'],
103
+ [
104
+ 'hubot',
105
+ '- `#489` - BROADWAY AVE & 12TH AVE N WB\n'
106
+ + '- `#4588` - BROADWAY AVE & 12TH AVE EB\n'
107
+ + '- `#5275` - 11TH AVE & PORTER ST SB\n'
108
+ + '- `#5281` - 11TH AVE & PORTER ST NB\n'
109
+ + '- `#4825` - BROADWAY & 10TH AVE EB',
110
+ ],
111
+ ]);
112
+ });
113
+ });
114
+
115
+ describe('regular tests with default stop ID set', () => {
116
+ beforeEach(async () => {
117
+ Date.now = () => Date.parse('Sun Aug 30 2026 12:58:00 GMT-0500 (Central Daylight Time)');
118
+ process.env.HUBOT_NEXTBUS_LAT_LON = '0,0';
119
+ process.env.HUBOT_NEXTBUS_STOP_ID = 'BRO12WN';
120
+ room = await helper.createRoom();
121
+ });
122
+
123
+ afterEach(() => {
124
+ room.destroy();
125
+ delete process.env.HUBOT_NEXTBUS_LAT_LON;
126
+ delete process.env.HUBOT_NEXTBUS_STOP_ID;
127
+ });
128
+
129
+ // hubot nextbus
130
+ it('returns the next bus for closest stop', async () => {
131
+ await room.user.say('alice', '@hubot nextbus');
132
+ await room.waitForMessages(3);
133
+ expect(room.messages).toEqual([
134
+ ['alice', '@hubot nextbus'],
135
+ [
136
+ 'hubot',
137
+ '⚠️ *6TH AVE & DEADERICK ST SB is not currently being served due to Construction.*\n'
138
+ + '⚠️ *Detour in effect on route 7 HILLSBORO TO DOWNTOWN*\n'
139
+ + '⚠️ *Detour in effect on route 7 HILLSBORO FROM DOWNTOWN*'],
140
+ [
141
+ 'hubot',
142
+ '🚏 *BROADWAY AVE & 12TH AVE N WB*\n'
143
+ + ' 1:01 PM #7 - GREEN HILLS 🚌 in 4 minutes (On time)\n'
144
+ + ' 1:06 PM #3 - B - BELLEVUE 🚌 in 9 minutes (On time)\n'
145
+ + ' 1:21 PM #3 - A -WHITE BRIDGE in 24 minutes (On time)\n'
146
+ + ' 1:21 PM #7 - GREEN HILLS in 24 minutes (On time)',
147
+ ],
148
+ ]);
149
+ });
150
+ });
151
+
152
+ describe('time spans days', () => {
153
+ beforeEach(async () => {
154
+ Date.now = () => Date.parse('Sun Aug 30 2026 12:58:00 GMT-0500 (Central Daylight Time)');
155
+ room = await helper.createRoom();
156
+ });
157
+
158
+ afterEach(() => {
159
+ room.destroy();
160
+ });
161
+
162
+ it('returns the next bus for specific stop', async () => {
163
+ await room.user.say('alice', '@hubot nextbus stop PORGRESF');
164
+ await room.waitForMessages(2);
165
+ expect(room.messages).toEqual([
166
+ ['alice', '@hubot nextbus stop PORGRESF'],
167
+ [
168
+ 'hubot',
169
+ '🚏 *PORTER RD & GREENWOOD AVE SB*\n'
170
+ + ' 1:40 PM #4 - DOWNTOWN in 42 minutes\n'
171
+ + ' 2:20 PM #4 - DOWNTOWN in an hour\n'
172
+ + ' 3:00 PM #4 - DOWNTOWN in 2 hours\n'
173
+ + ' 3:40 PM #4 - DOWNTOWN in 3 hours',
174
+ ],
175
+ ]);
176
+ });
177
+ });
178
+ });
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ exclude: ['**/node_modules/**', '**/helpers/**'],
7
+ coverage: {
8
+ provider: 'v8',
9
+ reporter: ['lcov', 'text', 'clover'],
10
+ reportsDirectory: './test-results',
11
+ exclude: ['**/node_modules/**'],
12
+ },
13
+ },
14
+ });