Skip to content

Commit a79675c

Browse files
committed
Include test files to typescript project files and fix type issues
1 parent cbe966e commit a79675c

23 files changed

Lines changed: 170 additions & 128 deletions

checkin/.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"extends": "@hakatashi",
2+
"extends": "@hakatashi/eslint-config/typescript",
33
"parserOptions": {
44
"ecmaVersion": 2017,
55
"ecmaFeatures": {

checkin/index.test.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@ describe('tiobot', () => {
5555
},
5656
};
5757

58-
const {text, username} = await slack.getResponseTo('checkin-check');
58+
const message = await slack.getResponseTo('checkin-check');
5959

60-
expect(username).toBe('checkin');
61-
expect(text).toContain('Koki Takahashi');
62-
expect(text).toContain('理学部7号館');
63-
expect(text).toContain('おるでw');
60+
// eslint-disable-next-line no-restricted-syntax
61+
expect('username' in message && message.username).toBe('checkin');
62+
expect(message.text).toContain('Koki Takahashi');
63+
expect(message.text).toContain('理学部7号館');
64+
expect(message.text).toContain('おるでw');
6465
});
6566
});

checkin/index.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ import get from 'lodash/get';
44
import schedule from 'node-schedule';
55
import logger from '../lib/logger';
66
import type {SlackInterface} from '../lib/slack';
7+
import type {MessageEvent} from '@slack/bolt';
8+
9+
interface User {
10+
firstName: string;
11+
lastName: string;
12+
photo: {
13+
prefix: string;
14+
suffix: string;
15+
};
16+
}
17+
18+
interface HereNowItem {
19+
id: string;
20+
user: User;
21+
shout?: string;
22+
}
723

824
const log = logger.child({bot: 'checkin'});
925

@@ -14,7 +30,7 @@ const places = [
1430

1531
export default ({eventClient, webClient: slack}: SlackInterface) => {
1632
const state = {
17-
herenow: new Map<string, any[]>(),
33+
herenow: new Map<string, HereNowItem[]>(),
1834
};
1935

2036
const job = async () => {
@@ -32,11 +48,11 @@ export default ({eventClient, webClient: slack}: SlackInterface) => {
3248
responseType: 'json',
3349
});
3450

35-
const items: any[] = get(data, ['data', 'response', 'hereNow', 'items'], []);
51+
const items: HereNowItem[] = get(data, ['data', 'response', 'hereNow', 'items'], []);
3652

3753
if (state.herenow.has(place.id)) {
3854
const newUsers = items.filter(({id}) => (
39-
state.herenow.get(place.id).find((user: any) => user.id === id) === undefined
55+
state.herenow.get(place.id).find((user) => user.id === id) === undefined
4056
));
4157

4258
for (const {user, shout} of newUsers) {
@@ -60,8 +76,8 @@ export default ({eventClient, webClient: slack}: SlackInterface) => {
6076
schedule.scheduleJob('*/3 * * * *', job);
6177
}
6278

63-
eventClient.on('message', (message: any) => {
64-
if (message.text === 'checkin-check' && message.channel === process.env.CHANNEL_SANDBOX) {
79+
eventClient.on('message', (message: MessageEvent) => {
80+
if ('text' in message && message.text === 'checkin-check' && message.channel === process.env.CHANNEL_SANDBOX) {
6581
job();
6682
}
6783
});

dajare/index.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
vi.mock('axios');
44
vi.mock('./tokenize.js');
5-
vi.mock('../achievements', () => ({unlock: vi.fn(), increment: vi.fn(), get: vi.fn(), set: vi.fn()}));
5+
vi.mock('../achievements');
66

77
const dajare = require('./index.js');
88
const {default: Slack} = require('../lib/slackMock.ts');

deploy/block.test.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/* eslint-disable require-await */
2+
3+
import {expect, it, beforeEach} from 'vitest';
14
import Blocker from './block';
25

36
let blocker: InstanceType<typeof Blocker> = null;
@@ -10,10 +13,10 @@ it('blocks until unblocked', () => new Promise<void>(async (resolve) => {
1013
const unblock = await blocker.block('block1');
1114
let blocked = true;
1215

13-
blocker.wait(() => {
16+
blocker.wait(async () => {
1417
expect(blocked).toBe(false);
1518
resolve();
16-
});
19+
}, 0);
1720

1821
process.nextTick(() => {
1922
blocked = false;
@@ -28,39 +31,41 @@ it('blocks until all unblocked', () => new Promise<void>(async (resolve) => {
2831
}
2932
let unblocked = 0;
3033

31-
blocker.wait(() => {
34+
blocker.wait(async () => {
3235
expect(unblocked).toBe(10);
3336
resolve();
34-
});
37+
}, 0);
3538

3639
while (unblocks.length > 0) {
3740
unblocked++;
3841
unblocks.shift()();
3942

40-
await new Promise((res) => process.nextTick(res));
43+
await new Promise((resolve) => process.nextTick(resolve));
4144
}
4245
}));
4346

4447
it('calls intervalCallback when block continues', () => new Promise<void>(async (resolve, reject) => {
4548
await blocker.block('block');
4649

47-
blocker.wait(reject as () => void, 0, resolve);
50+
blocker.wait(async () => {
51+
reject(new Error());
52+
}, 0, () => resolve());
4853
}));
4954

5055
it('does not call intervalCallback unless blocked', () => new Promise<void>(async (resolve, reject) => {
5156
const unblock = await blocker.block('block');
5257
unblock();
5358

54-
blocker.wait(() => {
59+
blocker.wait(async () => {
5560
process.nextTick(resolve);
56-
}, 0, reject as () => void);
61+
}, 0, reject);
5762
}));
5863

5964
it('cannot block while wait callback is runnning', () => new Promise<void>(async (resolve, reject) => {
6065
blocker.wait(() => new Promise<void>((callbackResolve) => process.nextTick(() => {
6166
resolve();
6267
callbackResolve();
63-
})));
68+
})), 0);
6469

6570
await blocker.block('block');
6671
reject(new Error());

discord/notifier.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ describe('discord', () => {
104104

105105
const slack = new Slack();
106106

107-
const postMessage = slack.webClient.chat.postMessage as vi.MockedFunction<typeof slack.webClient.chat.postMessage>;
107+
const postMessage = vi.mocked(slack.webClient.chat.postMessage);
108108
postMessage.mockResolvedValue({
109109
ok: true,
110110
ts: '123456789.123456',
@@ -165,7 +165,7 @@ describe('discord', () => {
165165

166166
const slack = new Slack();
167167

168-
const postMessage = slack.webClient.chat.postMessage as vi.MockedFunction<typeof slack.webClient.chat.postMessage>;
168+
const postMessage = vi.mocked(slack.webClient.chat.postMessage);
169169
postMessage.mockResolvedValue({
170170
ok: true,
171171
ts: '123456789.123456',
@@ -226,7 +226,7 @@ describe('discord', () => {
226226

227227
const slack = new Slack();
228228

229-
const postMessage = slack.webClient.chat.postMessage as vi.MockedFunction<typeof slack.webClient.chat.postMessage>;
229+
const postMessage = vi.mocked(slack.webClient.chat.postMessage);
230230
postMessage.mockResolvedValue({ok: false});
231231

232232
const notifier = new Notifier(slack.webClient);
@@ -242,7 +242,7 @@ describe('discord', () => {
242242

243243
const slack = new Slack();
244244

245-
const postMessage = slack.webClient.chat.postMessage as vi.MockedFunction<typeof slack.webClient.chat.postMessage>;
245+
const postMessage = vi.mocked(slack.webClient.chat.postMessage);
246246
postMessage.mockImplementation((message) => {
247247
if (message.channel === FAKE_SANDBOX) {
248248
return Promise.resolve({
@@ -260,7 +260,7 @@ describe('discord', () => {
260260

261261
await notifier.voiceStateUpdate(EMPTY_CHANNEL_STATE, JOINED_CHANNEL_STATE);
262262

263-
const deleteMessage = slack.webClient.chat.delete as vi.MockedFunction<typeof slack.webClient.chat.delete>;
263+
const deleteMessage = vi.mocked(slack.webClient.chat.delete);
264264
deleteMessage.mockResolvedValue({ok: true});
265265

266266
await notifier.voiceStateUpdate(JOINED_CHANNEL_STATE, EMPTY_CHANNEL_STATE);
@@ -278,7 +278,7 @@ describe('discord', () => {
278278

279279
const slack = new Slack();
280280

281-
const postMessage = slack.webClient.chat.postMessage as vi.MockedFunction<typeof slack.webClient.chat.postMessage>;
281+
const postMessage = vi.mocked(slack.webClient.chat.postMessage);
282282
postMessage.mockResolvedValue({
283283
ok: true,
284284
ts: '123456789.123456',

helloworld/HelloWorld.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ describe('helloworld', () => {
5252
});
5353

5454
it('can post Hello world message', async () => {
55-
const postMessage = slack.webClient.chat.postMessage as vi.MockedFunction<typeof slack.webClient.chat.postMessage>;
55+
const postMessage = vi.mocked(slack.webClient.chat.postMessage);
5656
postMessage.mockResolvedValueOnce({
5757
ok: true,
5858
ts: slack.fakeTimestamp,
@@ -69,7 +69,7 @@ describe('helloworld', () => {
6969
channel: slack.fakeChannel,
7070
});
7171

72-
const mockedPostMessage = slack.webClient.chat.postMessage as vi.MockedFunction<typeof slack.webClient.chat.postMessage>;
72+
const mockedPostMessage = vi.mocked(slack.webClient.chat.postMessage);
7373
expect(mockedPostMessage).toBeCalledWith({
7474
username: 'helloworld [TEST_AUTHORITY]',
7575
channel: slack.fakeChannel,

lib/channelLimitedBot.test.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {GenericMessageEvent} from '@slack/web-api';
22
import {ChannelLimitedBot} from './channelLimitedBot';
33
import Slack from './slackMock';
4+
import type {Mock} from 'vitest';
45

56
vi.mock('../lib/slackUtils');
67

@@ -13,25 +14,25 @@ describe('ChannelLimitedBot', () => {
1314
process.env.CHANNEL_GAMES = slack.fakeChannel;
1415
process.env.HAKATASHI_TOKEN = 'xoxb-hakatashi-token';
1516

16-
(slack.webClient.chat.getPermalink as vi.Mock).mockResolvedValue({
17+
(slack.webClient.chat.getPermalink as Mock).mockResolvedValue({
1718
ok: true,
1819
permalink: 'https://slack.com/archives/CHANNEL_ID/p1234567890123456',
1920
});
20-
(slack.webClient.chat.postEphemeral as vi.Mock).mockResolvedValue({
21+
(slack.webClient.chat.postEphemeral as Mock).mockResolvedValue({
2122
ok: true,
2223
message_ts: '12345.6789',
2324
});
24-
(slack.webClient.chat.postMessage as vi.Mock).mockResolvedValue({
25+
(slack.webClient.chat.postMessage as Mock).mockResolvedValue({
2526
ok: true,
2627
ts: 'progress.123',
2728
});
28-
(slack.webClient.chat.delete as vi.Mock).mockResolvedValue({
29+
(slack.webClient.chat.delete as Mock).mockResolvedValue({
2930
ok: true,
3031
});
3132
});
3233

3334
it('responds to messages containing the wake word in the allowed channel', async () => {
34-
const onWakeWord = vi.fn<Promise<string | null>, [GenericMessageEvent, string]>();
35+
const onWakeWord = vi.fn<(message: GenericMessageEvent, channel: string) => Promise<string | null>>();
3536

3637
class TestBot extends ChannelLimitedBot {
3738
protected override wakeWordRegex = /wakeword/;
@@ -52,7 +53,7 @@ describe('ChannelLimitedBot', () => {
5253
});
5354

5455
it('posts ephemeral message and deletes original when wake word is used in disallowed channel (null response)', async () => {
55-
const onWakeWord = vi.fn<Promise<string | null>, [GenericMessageEvent, string]>();
56+
const onWakeWord = vi.fn<(message: GenericMessageEvent, channel: string) => Promise<string | null>>();
5657
const disallowedChannel = 'C9876543210';
5758

5859
class TestBot extends ChannelLimitedBot {
@@ -89,7 +90,7 @@ describe('ChannelLimitedBot', () => {
8990
});
9091

9192
it('posts ephemeral message with permalink and deletes original when wake word is used in disallowed channel (with response)', async () => {
92-
const onWakeWord = vi.fn<Promise<string | null>, [GenericMessageEvent, string]>();
93+
const onWakeWord = vi.fn<(message: GenericMessageEvent, channel: string) => Promise<string | null>>();
9394
const disallowedChannel = 'C9876543210';
9495
const responseTs = '12345.6789';
9596
const progressChannel = 'CPROGRESS';
@@ -134,7 +135,7 @@ describe('ChannelLimitedBot', () => {
134135
});
135136

136137
it('ignores messages without the wake word', async () => {
137-
const onWakeWord = vi.fn<Promise<string | null>, [GenericMessageEvent, string]>();
138+
const onWakeWord = vi.fn<(message: GenericMessageEvent, channel: string) => Promise<string | null>>();
138139

139140
class TestBot extends ChannelLimitedBot {
140141
protected override wakeWordRegex = /wakeword/;
@@ -149,7 +150,7 @@ describe('ChannelLimitedBot', () => {
149150
});
150151

151152
it('ignores messages from bots', async () => {
152-
const onWakeWord = vi.fn<Promise<string | null>, [GenericMessageEvent, string]>();
153+
const onWakeWord = vi.fn<(message: GenericMessageEvent, channel: string) => Promise<string | null>>();
153154

154155
class TestBot extends ChannelLimitedBot {
155156
protected override wakeWordRegex = /wakeword/;
@@ -167,7 +168,7 @@ describe('ChannelLimitedBot', () => {
167168
});
168169

169170
it('ignores messages without user', async () => {
170-
const onWakeWord = vi.fn<Promise<string | null>, [GenericMessageEvent, string]>();
171+
const onWakeWord = vi.fn<(message: GenericMessageEvent, channel: string) => Promise<string | null>>();
171172

172173
class TestBot extends ChannelLimitedBot {
173174
protected override wakeWordRegex = /wakeword/;
@@ -187,7 +188,7 @@ describe('ChannelLimitedBot', () => {
187188
});
188189

189190
it('ignores messages without text', async () => {
190-
const onWakeWord = vi.fn<Promise<string | null>, [GenericMessageEvent, string]>();
191+
const onWakeWord = vi.fn<(message: GenericMessageEvent, channel: string) => Promise<string | null>>();
191192

192193
class TestBot extends ChannelLimitedBot {
193194
protected override wakeWordRegex = /wakeword/;

lib/download.test.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import axios from 'axios';
22
import fs from 'node:fs';
33
import { PassThrough } from 'stream';
44
import { download } from './download';
5+
import type { Mock } from 'vitest';
56

67
vi.mock('axios');
78
vi.mock('node:fs', () => {
@@ -21,7 +22,7 @@ const fakePath = '~/fake/path';
2122
const fakeUrl = 'https://www.example.com';
2223

2324
beforeAll(() => {
24-
(<vi.Mock> axios.get).mockImplementation(() => {
25+
(<Mock> axios.get).mockImplementation(() => {
2526
const stream = new PassThrough();
2627
process.nextTick(() => {
2728
stream.end(fakeData);
@@ -35,12 +36,12 @@ beforeEach(() => {
3536
});
3637

3738
it('downloads fetched data to path', async () => {
38-
(<vi.Mock> (fs.access as any)).mockImplementation((_, __, callback) => {
39+
(<Mock> (fs.access as any)).mockImplementation((_, __, callback) => {
3940
callback(true);
4041
});
4142
await Promise.all([
4243
new Promise<void>((resolve) => {
43-
(<vi.Mock> fs.createWriteStream).mockReturnValue(
44+
(<Mock> fs.createWriteStream).mockReturnValue(
4445
new PassThrough().on('data', (data) => {
4546
expect(data).toBe(fakeData)
4647
resolve();
@@ -49,17 +50,17 @@ it('downloads fetched data to path', async () => {
4950
}),
5051
download(fakePath, fakeUrl)
5152
]);
52-
expect((<vi.Mock> axios.get).mock.calls.length).toBe(1);
53-
expect((<vi.Mock> axios.get).mock.calls[0][0]).toBe(fakeUrl);
54-
expect((<vi.Mock> fs.createWriteStream).mock.calls.length).toBe(1);
55-
expect((<vi.Mock> fs.createWriteStream).mock.calls[0][0]).toBe(fakePath);
53+
expect((<Mock> axios.get).mock.calls.length).toBe(1);
54+
expect((<Mock> axios.get).mock.calls[0][0]).toBe(fakeUrl);
55+
expect((<Mock> fs.createWriteStream).mock.calls.length).toBe(1);
56+
expect((<Mock> fs.createWriteStream).mock.calls[0][0]).toBe(fakePath);
5657
});
5758

5859
it('does not download when file exists', async () => {
59-
(<vi.Mock> (fs.access as any)).mockImplementation((_, __, callback) => {
60+
(<Mock> (fs.access as any)).mockImplementation((_, __, callback) => {
6061
callback(false);
6162
});
6263
await download(fakePath, fakeUrl);
63-
expect((<vi.Mock> axios.get).mock.calls.length).toBe(0);
64-
expect((<vi.Mock> fs.createWriteStream).mock.calls.length).toBe(0);
64+
expect((<Mock> axios.get).mock.calls.length).toBe(0);
65+
expect((<Mock> fs.createWriteStream).mock.calls.length).toBe(0);
6566
});

lib/eventDeduplication.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import {
33
closeDuplicateEventChecker,
44
} from './eventDeduplication';
55
import { createClient } from 'redis';
6+
import type { Mock, Mocked } from 'vitest';
67

78
const mockRedis: Pick<
8-
vi.Mocked<ReturnType<typeof createClient>>,
9-
'set' | 'connect' | 'quit' | 'on'
10-
> = {
9+
Mocked<ReturnType<typeof createClient>>,
10+
'set' | 'connect' | 'quit'
11+
> & {on: Mock<ReturnType<typeof createClient>['on']>} = {
1112
set: vi.fn(),
1213
connect: vi.fn(),
1314
quit: vi.fn(),

0 commit comments

Comments
 (0)