11import moment from 'moment' ;
2+ import schedule , { Job , JobCallback } from 'node-schedule' ;
3+ import { unlock , increment } from '../achievements' ;
4+ import State from '../lib/state' ;
5+ import { MockedStateInterface } from '../lib/__mocks__/state' ;
26import sushi from './index.js' ;
37import Slack from '../lib/slackMock' ;
48
59vi . mock ( '../achievements' ) ;
610vi . mock ( 'moment' ) ;
711vi . mock ( '../lib/state' ) ;
12+ vi . mock ( 'node-schedule' , ( ) => ( {
13+ default : {
14+ scheduleJob : vi . fn ( ) ,
15+ } ,
16+ scheduleJob : vi . fn ( ) ,
17+ } ) ) ;
818vi . mock ( 'fs-extra' , ( ) => ( {
919 mkdirp : vi . fn ( ) ,
1020 readFile : vi . fn ( ( ) => Promise . resolve ( Buffer . from ( '' ) ) ) ,
@@ -13,11 +23,18 @@ vi.mock('fs-extra', () => ({
1323} ) ) ;
1424
1525let slack : InstanceType < typeof Slack > = null ;
26+ let scheduleCallback : JobCallback | null = null ;
1627
1728describe ( 'sushi-bot' , async ( ) => {
1829 const originalMoment = ( await vi . importActual < { default : typeof import ( 'moment' ) } > ( 'moment' ) ) . default ;
1930
2031 beforeEach ( async ( ) => {
32+ vi . clearAllMocks ( ) ;
33+ scheduleCallback = null ;
34+ vi . mocked ( schedule . scheduleJob ) . mockImplementation ( ( rule , fn ) => {
35+ scheduleCallback = fn ;
36+ return { } as Job ;
37+ } ) ;
2138 slack = new Slack ( ) ;
2239 await sushi ( slack ) ;
2340
@@ -464,4 +481,89 @@ describe('sushi-bot', async () => {
464481 ts : slack . fakeTimestamp ,
465482 } ) ;
466483 } ) ) ;
484+
485+ describe ( 'weekly wakeup ranking achievements' , ( ) => {
486+ beforeEach ( ( ) => {
487+ vi . mocked ( slack . webClient . users . list ) . mockResolvedValue ( {
488+ ok : true ,
489+ members : [
490+ {
491+ id : slack . fakeUser ,
492+ name : 'fakeUser' ,
493+ profile : {
494+ display_name : 'Fake User' ,
495+ image_24 : 'https://example.com/image.png' ,
496+ } ,
497+ } ,
498+ ] ,
499+ } ) ;
500+ } ) ;
501+
502+ it ( 'unlocks "起床フィーバータイム" (asa-week-repdigit) when score is a 3-digit repdigit (e.g. 333)' , async ( ) => {
503+ const mockedState = State as MockedStateInterface < any > ;
504+ const state = mockedState . mocks . get ( 'sushi-bot-counter-asa' ) ;
505+ state . data = { [ slack . fakeUser ] : 333 } ;
506+
507+ expect ( scheduleCallback ) . not . toBeNull ( ) ;
508+ // 2023-01-01 is a Sunday!
509+ await scheduleCallback ! ( new Date ( '2023-01-01T19:00:00+09:00' ) ) ;
510+
511+ expect ( increment ) . toHaveBeenCalledWith ( slack . fakeUser , 'asa-week-repdigit' ) ;
512+ } ) ;
513+
514+ it ( 'does not unlock "起床フィーバータイム" when score is not a 3-digit repdigit (e.g. 334)' , async ( ) => {
515+ const mockedState = State as MockedStateInterface < any > ;
516+ const state = mockedState . mocks . get ( 'sushi-bot-counter-asa' ) ;
517+ state . data = { [ slack . fakeUser ] : 334 } ;
518+
519+ expect ( scheduleCallback ) . not . toBeNull ( ) ;
520+ await scheduleCallback ! ( new Date ( '2023-01-01T19:00:00+09:00' ) ) ;
521+
522+ expect ( increment ) . not . toHaveBeenCalledWith ( slack . fakeUser , 'asa-week-repdigit' ) ;
523+ } ) ;
524+
525+ it ( 'unlocks "起床ロボット" (asa-week-power-of-two) when score is a power of 2 (e.g. 256)' , async ( ) => {
526+ const mockedState = State as MockedStateInterface < any > ;
527+ const state = mockedState . mocks . get ( 'sushi-bot-counter-asa' ) ;
528+ state . data = { [ slack . fakeUser ] : 256 } ;
529+
530+ expect ( scheduleCallback ) . not . toBeNull ( ) ;
531+ await scheduleCallback ! ( new Date ( '2023-01-01T19:00:00+09:00' ) ) ;
532+
533+ expect ( increment ) . toHaveBeenCalledWith ( slack . fakeUser , 'asa-week-power-of-two' ) ;
534+ } ) ;
535+
536+ it ( 'does not unlock "起床ロボット" when score is not a power of 2 (e.g. 255)' , async ( ) => {
537+ const mockedState = State as MockedStateInterface < any > ;
538+ const state = mockedState . mocks . get ( 'sushi-bot-counter-asa' ) ;
539+ state . data = { [ slack . fakeUser ] : 255 } ;
540+
541+ expect ( scheduleCallback ) . not . toBeNull ( ) ;
542+ await scheduleCallback ! ( new Date ( '2023-01-01T19:00:00+09:00' ) ) ;
543+
544+ expect ( increment ) . not . toHaveBeenCalledWith ( slack . fakeUser , 'asa-week-power-of-two' ) ;
545+ } ) ;
546+
547+ it ( 'unlocks "なんでや" (asa-week-334) when score is exactly 334' , async ( ) => {
548+ const mockedState = State as MockedStateInterface < any > ;
549+ const state = mockedState . mocks . get ( 'sushi-bot-counter-asa' ) ;
550+ state . data = { [ slack . fakeUser ] : 334 } ;
551+
552+ expect ( scheduleCallback ) . not . toBeNull ( ) ;
553+ await scheduleCallback ! ( new Date ( '2023-01-01T19:00:00+09:00' ) ) ;
554+
555+ expect ( increment ) . toHaveBeenCalledWith ( slack . fakeUser , 'asa-week-334' ) ;
556+ } ) ;
557+
558+ it ( 'does not unlock "なんでや" when score is not exactly 334 (e.g. 333)' , async ( ) => {
559+ const mockedState = State as MockedStateInterface < any > ;
560+ const state = mockedState . mocks . get ( 'sushi-bot-counter-asa' ) ;
561+ state . data = { [ slack . fakeUser ] : 333 } ;
562+
563+ expect ( scheduleCallback ) . not . toBeNull ( ) ;
564+ await scheduleCallback ! ( new Date ( '2023-01-01T19:00:00+09:00' ) ) ;
565+
566+ expect ( increment ) . not . toHaveBeenCalledWith ( slack . fakeUser , 'asa-week-334' ) ;
567+ } ) ;
568+ } ) ;
467569} ) ;
0 commit comments