test: extract computeWordClass tests to dedicated file

- Move computeWordClass tests from subtitle-render.test.ts to subtitle-render-word-class.test.ts
- Extract createToken helper into subtitle-render-test-helpers.ts for reuse
- Register new test file in test:core:src and test:core:dist scripts
This commit is contained in:
2026-05-20 22:34:45 -07:00
parent 525cb7e1fd
commit 47f92129af
4 changed files with 226 additions and 219 deletions
@@ -0,0 +1,206 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import type { MergedToken } from '../types';
import { computeWordClass } from './subtitle-render.js';
import { createToken } from './subtitle-render-test-helpers.js';
test('computeWordClass preserves known and n+1 classes while adding JLPT classes', () => {
const knownJlpt = createToken({
isKnown: true,
jlptLevel: 'N1',
surface: '猫',
});
const nPlusOneJlpt = createToken({
isNPlusOneTarget: true,
jlptLevel: 'N2',
surface: '犬',
});
assert.equal(computeWordClass(knownJlpt), 'word word-known word-jlpt-n1');
assert.equal(computeWordClass(nPlusOneJlpt), 'word word-n-plus-one word-jlpt-n2');
});
test('computeWordClass applies name-match class ahead of known, n+1, frequency, and JLPT classes when enabled', () => {
const token = createToken({
isKnown: true,
isNPlusOneTarget: true,
jlptLevel: 'N2',
frequencyRank: 10,
surface: 'アクア',
}) as MergedToken & { isNameMatch?: boolean };
token.isNameMatch = true;
assert.equal(
computeWordClass(token, {
nameMatchEnabled: true,
enabled: true,
topX: 100,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
}),
'word word-name-match',
);
});
test('computeWordClass skips name-match class by default', () => {
const token = createToken({
surface: 'アクア',
}) as MergedToken & { isNameMatch?: boolean };
token.isNameMatch = true;
assert.equal(computeWordClass(token), 'word');
});
test('computeWordClass skips name-match class when disabled', () => {
const token = createToken({
surface: 'アクア',
}) as MergedToken & { isNameMatch?: boolean };
token.isNameMatch = true;
assert.equal(
computeWordClass(token, {
nameMatchEnabled: false,
enabled: true,
topX: 100,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
}),
'word',
);
});
test('computeWordClass keeps known and N+1 color classes exclusive over frequency classes', () => {
const known = createToken({
isKnown: true,
frequencyRank: 10,
surface: '既知',
});
const nPlusOne = createToken({
isNPlusOneTarget: true,
frequencyRank: 10,
surface: '目標',
});
const frequency = createToken({
frequencyRank: 10,
surface: '頻度',
});
assert.equal(
computeWordClass(known, {
enabled: true,
topX: 100,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
}),
'word word-known',
);
assert.equal(
computeWordClass(nPlusOne, {
enabled: true,
topX: 100,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
}),
'word word-n-plus-one',
);
assert.equal(
computeWordClass(frequency, {
enabled: true,
topX: 100,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
}),
'word word-frequency-single',
);
});
test('computeWordClass adds frequency class for single mode when rank is within topX', () => {
const token = createToken({
surface: '猫',
frequencyRank: 50,
});
const actual = computeWordClass(token, {
enabled: true,
topX: 100,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
});
assert.equal(actual, 'word word-frequency-single');
});
test('computeWordClass adds frequency class when rank equals topX', () => {
const token = createToken({
surface: '水',
frequencyRank: 100,
});
const actual = computeWordClass(token, {
enabled: true,
topX: 100,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
});
assert.equal(actual, 'word word-frequency-single');
});
test('computeWordClass adds frequency class for banded mode', () => {
const token = createToken({
surface: '犬',
frequencyRank: 250,
});
const actual = computeWordClass(token, {
enabled: true,
topX: 1000,
mode: 'banded',
singleColor: '#000000',
bandedColors: ['#111111', '#222222', '#333333', '#444444', '#555555'] as const,
});
assert.equal(actual, 'word word-frequency-band-2');
});
test('computeWordClass uses configured band count for banded mode', () => {
const token = createToken({
surface: '犬',
frequencyRank: 2,
});
const actual = computeWordClass(token, {
enabled: true,
topX: 4,
mode: 'banded',
singleColor: '#000000',
bandedColors: ['#111111', '#222222', '#333333', '#444444', '#555555'],
} as any);
assert.equal(actual, 'word word-frequency-band-3');
});
test('computeWordClass skips frequency class when rank is out of topX', () => {
const token = createToken({
surface: '犬',
frequencyRank: 1200,
});
const actual = computeWordClass(token, {
enabled: true,
topX: 1000,
mode: 'single',
singleColor: '#000000',
bandedColors: ['#000000', '#000000', '#000000', '#000000', '#000000'] as const,
});
assert.equal(actual, 'word');
});