Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion docs/guides/how-to-add-contest-table-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,59 @@ describe('MyNewProvider', () => {
});
```

### prepareContestProviderPresets() のテスト

Provider クラスのテスト完了後、`prepareContestProviderPresets()` から返されるグループ(`ContestTableProviderGroup`)の動作を検証します。

**テスト項目**:

1. **グループ名の確認**

```typescript
const group = prepareContestProviderPresets().MyNewProvider();
expect(group.getGroupName()).toBe('Expected Group Name');
```

2. **グループメタデータの確認**(`buttonLabel`、`ariaLabel`)

```typescript
expect(group.getMetadata()).toEqual({
buttonLabel: 'Button Label',
ariaLabel: 'ARIA Label',
});
```

3. **プロバイダー数の確認**
- **単一プロバイダーグループ**: `getSize()` が 1 を返す
- **複数プロバイダーグループ**: `getSize()` が複数を返す(例:ACL は 3)

4. **プロバイダーインスタンス型の確認**
- **単一プロバイダー**:
```typescript
expect(group.getProvider(ContestType.MY_NEW)).toBeInstanceOf(MyNewProvider);
```
- **複数プロバイダー**(セクション指定あり):
```typescript
expect(group.getProvider(ContestType.TESSOKU_BOOK, 'examples')).toBeInstanceOf(
TessokuBookForExamplesProvider,
);
expect(group.getProvider(ContestType.TESSOKU_BOOK, 'practicals')).toBeInstanceOf(
TessokuBookForPracticalsProvider,
);
```

**セクション識別子の指定**:

複数プロバイダーを含むグループでは、`getProvider()` の第2引数にセクション識別子を渡します。セクション定数は `src/lib/types/contest_table_provider.ts` で定義されています:

- `TESSOKU_SECTIONS`: `examples`、`practicals`、`challenges`
- `JOI_SECOND_QUAL_ROUND_SECTIONS`: `'2020Onwards'`、`from2006To2019`
- `JOI_FINAL_ROUND_SECTIONS`: `semiFinal`

詳細な実装例は [単体テストファイル](../src/test/lib/utils/contest_table_provider.test.ts) を参照してください。

---

### モックデータ準備

**ステップ1: データソース確認**
Expand Down Expand Up @@ -479,4 +532,4 @@ describe('CustomProvider with unique config', () => {

---

**最終更新**: 2026-02-01
**最終更新**: 2026-02-05
6 changes: 3 additions & 3 deletions src/lib/utils/contest_table_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,7 @@ export const prepareContestProviderPresets = () => {
*/
Acl: () =>
new ContestTableProviderGroup(`AtCoder Library Contests`, {
buttonLabel: 'ACL',
buttonLabel: 'AtCoder Library (ACL)',
ariaLabel: 'Filter ACL Contests',
}).addProviders(
new ACLPracticeProvider(ContestType.ACL_PRACTICE),
Expand All @@ -1293,8 +1293,8 @@ export const prepareContestProviderPresets = () => {
}).addProvider(new JOIFirstQualRoundProvider(ContestType.JOI)),

JOISecondQualAndSemiFinalRound: () =>
new ContestTableProviderGroup(`JOI 二次予選・予選(旧形式)・本選`, {
buttonLabel: 'JOI 二次予選・予選(旧形式)・本選',
new ContestTableProviderGroup(`JOI 二次予選・本選`, {
buttonLabel: 'JOI 二次予選・本選',
ariaLabel: 'Filter JOI Second Qual Round',
}).addProviders(
new JOISecondQualRound2020OnwardsProvider(ContestType.JOI),
Expand Down
87 changes: 73 additions & 14 deletions src/test/lib/utils/contest_table_provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2937,20 +2937,6 @@ describe('prepareContestProviderPresets', () => {
expect(group.getProvider(ContestType.ABC)).toBeInstanceOf(ABC212ToABC318Provider);
});

test('expects to create DPs preset correctly', () => {
const group = prepareContestProviderPresets().dps();

expect(group.getGroupName()).toBe('EDPC・TDPC・FPS 24');
expect(group.getMetadata()).toEqual({
buttonLabel: 'EDPC・TDPC・FPS 24',
ariaLabel: 'EDPC and TDPC and FPS 24 contests',
});
expect(group.getSize()).toBe(3);
expect(group.getProvider(ContestType.EDPC)).toBeInstanceOf(EDPCProvider);
expect(group.getProvider(ContestType.TDPC)).toBeInstanceOf(TDPCProvider);
expect(group.getProvider(ContestType.FPS_24)).toBeInstanceOf(FPS24Provider);
});

test('expects to create Typical90 preset correctly', () => {
const group = prepareContestProviderPresets().Typical90();

Expand Down Expand Up @@ -2983,14 +2969,87 @@ describe('prepareContestProviderPresets', () => {
);
});

test('expects to create DPs preset correctly', () => {
const group = prepareContestProviderPresets().dps();

expect(group.getGroupName()).toBe('EDPC・TDPC・FPS 24');
expect(group.getMetadata()).toEqual({
buttonLabel: 'EDPC・TDPC・FPS 24',
ariaLabel: 'EDPC and TDPC and FPS 24 contests',
});
expect(group.getSize()).toBe(3);
expect(group.getProvider(ContestType.EDPC)).toBeInstanceOf(EDPCProvider);
expect(group.getProvider(ContestType.TDPC)).toBeInstanceOf(TDPCProvider);
expect(group.getProvider(ContestType.FPS_24)).toBeInstanceOf(FPS24Provider);
});

test('expects to create ACL preset correctly with 3 providers', () => {
const group = prepareContestProviderPresets().Acl();

expect(group.getGroupName()).toBe('AtCoder Library Contests');
expect(group.getMetadata()).toEqual({
buttonLabel: 'AtCoder Library (ACL)',
ariaLabel: 'Filter ACL Contests',
});
expect(group.getSize()).toBe(3);
expect(group.getProvider(ContestType.ACL_PRACTICE)).toBeInstanceOf(ACLPracticeProvider);
expect(group.getProvider(ContestType.ABC_LIKE)).toBeInstanceOf(ACLBeginnerProvider);
expect(group.getProvider(ContestType.ARC_LIKE)).toBeInstanceOf(ACLProvider);
});

test('expects to create JOI First Qual Round preset correctly with 1 provider', () => {
const group = prepareContestProviderPresets().JOIFirstQualRound();

expect(group.getGroupName()).toBe('JOI 一次予選');
expect(group.getMetadata()).toEqual({
buttonLabel: 'JOI 一次予選',
ariaLabel: 'Filter JOI First Qualifying Round',
});
expect(group.getSize()).toBe(1);
expect(group.getProvider(ContestType.JOI)).toBeInstanceOf(JOIFirstQualRoundProvider);
});

test('expects to create JOI Second Qual and Semi-Final Round preset correctly with 3 providers', () => {
const group = prepareContestProviderPresets().JOISecondQualAndSemiFinalRound();

expect(group.getGroupName()).toBe('JOI 二次予選・本選');
expect(group.getMetadata()).toEqual({
buttonLabel: 'JOI 二次予選・本選',
ariaLabel: 'Filter JOI Second Qual Round',
});
expect(group.getSize()).toBe(3);
expect(group.getProvider(ContestType.JOI, '2020Onwards')).toBeInstanceOf(
JOISecondQualRound2020OnwardsProvider,
);
expect(group.getProvider(ContestType.JOI, 'from2006To2019')).toBeInstanceOf(
JOIQualRoundFrom2006To2019Provider,
);
expect(group.getProvider(ContestType.JOI, 'semiFinal')).toBeInstanceOf(
JOISemiFinalRoundProvider,
);
});

test('expects to verify all presets are functions', () => {
const presets = prepareContestProviderPresets();

expect(typeof presets.ABS).toBe('function');
expect(typeof presets.ABC319Onwards).toBe('function');
expect(typeof presets.ABC212ToABC318).toBe('function');
expect(typeof presets.ABC126ToABC211).toBe('function');
expect(typeof presets.ABC042ToABC125).toBe('function');
expect(typeof presets.ARC104Onwards).toBe('function');
expect(typeof presets.ARC058ToARC103).toBe('function');
expect(typeof presets.AGC001Onwards).toBe('function');
expect(typeof presets.ABCLike).toBe('function');
expect(typeof presets.ABC001ToABC041).toBe('function');
expect(typeof presets.ARC001ToARC057).toBe('function');
expect(typeof presets.Typical90).toBe('function');
expect(typeof presets.TessokuBook).toBe('function');
expect(typeof presets.MathAndAlgorithm).toBe('function');
expect(typeof presets.dps).toBe('function');
expect(typeof presets.Acl).toBe('function');
expect(typeof presets.JOIFirstQualRound).toBe('function');
expect(typeof presets.JOISecondQualAndSemiFinalRound).toBe('function');
});

test('expects each preset to create independent instances', () => {
Expand Down
Loading