refactor SettingTab, move strings to constants, add tests for display

This commit is contained in:
Mike Rodarte 2025-04-09 17:10:53 -04:00
parent 48091a4d27
commit 83c5bba2cc
No known key found for this signature in database
GPG key ID: 32DCD8C789A592CC
5 changed files with 81 additions and 17 deletions

View file

@ -9,7 +9,7 @@ module.exports = {
coverageThreshold: {
global: {
branches: 90,
functions: 70,
functions: 80,
lines: 90,
statements: 90,
},

View file

@ -1,14 +1,25 @@
import { PluginSettingTab, Setting } from 'obsidian';
import { VIEW_TYPE } from './constants';
import {
ELEMENT_CLASSES,
SettingFactory,
SETTINGS_DESCRIPTIONS,
SETTINGS_NAMES,
VIEW_TYPE,
} from './constants';
import WordFrequencyPlugin from './main';
import { WordFrequencyView } from './WordFrequencyView';
export class WordFrequencySettingTab extends PluginSettingTab {
plugin: WordFrequencyPlugin;
private settingFactory: SettingFactory;
constructor(plugin: WordFrequencyPlugin) {
constructor(
plugin: WordFrequencyPlugin,
settingFactory: SettingFactory = (el) => new Setting(el)
) {
super(plugin.app, plugin);
this.plugin = plugin;
this.settingFactory = settingFactory;
}
display(): void {
@ -16,22 +27,22 @@ export class WordFrequencySettingTab extends PluginSettingTab {
containerEl.empty();
const blacklist = new Setting(containerEl)
.setName('Blacklist')
.setDesc('Comma-separated list of words to exclude.')
.setClass('word-frequency-setting-item')
const blacklist = this.settingFactory(containerEl)
.setName(SETTINGS_NAMES.blacklist)
.setDesc(SETTINGS_DESCRIPTIONS.blacklist)
.setClass(ELEMENT_CLASSES.settingItem)
.addTextArea((text) => {
text.setValue(this.plugin.settings.blacklist)
.onChange(async (value) => {
await this.saveBlacklistValue(value);
})
.inputEl.classList.add('word-frequency-setting-blacklist');
.inputEl.classList.add(ELEMENT_CLASSES.settingBlacklist);
});
blacklist.infoEl.addClass('word-frequency-setting-item-info');
blacklist.infoEl.addClass(ELEMENT_CLASSES.settingInfoItem);
new Setting(containerEl)
.setName('Word frequency threshold')
.setDesc('Only show words that appear at least this many times.')
this.settingFactory(containerEl)
.setName(SETTINGS_NAMES.threshold)
.setDesc(SETTINGS_DESCRIPTIONS.threshold)
.addText((text) =>
text
.setPlaceholder('3')

View file

@ -46,7 +46,47 @@ describe('WordFrequencySettingTab', () => {
expect(settingTab.plugin).toBe(plugin);
});
it.todo('should create new settings');
it('should create new settings', () => {
const mockSetName = jest.fn().mockReturnThis();
const mockSetDesc = jest.fn().mockReturnThis();
const mockSetClass = jest.fn().mockReturnThis();
const mockAddTextArea = jest.fn().mockImplementation((cb) => {
cb({
setValue: jest.fn().mockReturnThis(),
onChange: jest.fn().mockReturnThis(),
inputEl: { classList: { add: jest.fn() } },
});
return mockSetting;
});
const mockAddText = jest.fn().mockImplementation((cb) => {
cb({
setPlaceholder: jest.fn().mockReturnThis(),
setValue: jest.fn().mockReturnThis(),
onChange: jest.fn(),
});
return mockSetting;
});
const mockSetting = {
setName: mockSetName,
setDesc: mockSetDesc,
setClass: mockSetClass,
addTextArea: mockAddTextArea,
addText: mockAddText,
infoEl: { addClass: jest.fn() },
};
const mockSettingFactory = jest.fn().mockReturnValue(mockSetting);
const settingTab = new WordFrequencySettingTab(
plugin,
mockSettingFactory
);
settingTab.containerEl = containerEl;
settingTab.display();
expect(mockSettingFactory).toHaveBeenCalledTimes(2);
expect(mockSetName).toHaveBeenCalledWith('Blacklist');
expect(mockAddTextArea).toHaveBeenCalled();
});
it('should save blacklist', async () => {
const value = 'word1,word2';

View file

@ -7,7 +7,6 @@ import {
} from '../constants';
import WordFrequencyPlugin from '../main';
import { ViewManager } from '../ViewManager';
import { WordFrequencySettingTab } from '../WordFrequencySettingTab';
import { WordFrequencyCounter } from '../WordFrequencyCounter';
import { WordFrequencyView } from '../WordFrequencyView';
@ -76,8 +75,6 @@ describe('WordFrequencyPlugin', () => {
describe('onload', () => {
it('should set up the plugin', async () => {
const settingTab = new WordFrequencySettingTab(plugin);
await plugin.onload();
expect(plugin.frequencyCounter).toBeInstanceOf(
@ -96,7 +93,7 @@ describe('WordFrequencyPlugin', () => {
'active-leaf-change',
expect.any(Function)
);
expect(plugin.addSettingTab).toHaveBeenCalledWith(settingTab);
expect(plugin.addSettingTab).toHaveBeenCalled();
});
it('should set up the plugin and respond to callbacks', async () => {

View file

@ -1,8 +1,13 @@
import { Setting } from 'obsidian';
// TODO: move non-constants out of this file
export interface WordFrequencySettings {
blacklist: string;
threshold: number;
}
export type SettingFactory = (containerEl: HTMLElement) => Setting;
export const DEFAULT_SETTINGS: WordFrequencySettings = {
blacklist: 'the,and,to,of,a,in,for,on,is,it,that,with,as,this,by,your,you',
threshold: 3,
@ -17,9 +22,20 @@ export const ELEMENT_CLASSES = {
containerThreshold: 'word-frequency-threshold-display',
containerWordList: 'word-frequency-word-list',
filter: 'word-frequency-filter',
settingBlacklist: 'word-frequency-setting-blacklist',
settingInfoItem: 'word-frequency-setting-item-info',
settingItem: 'word-frequency-setting-item',
};
export const EVENT_UPDATE = 'word-frequency-update';
export const FREQUENCY_ICON = 'file-chart-column-increasing';
export const PLUGIN_NAME = 'Word frequency';
export const SETTINGS_DESCRIPTIONS = {
blacklist: 'Comma-separated list of words to exclude.',
threshold: 'Only show words that appear at least this many times.',
};
export const SETTINGS_NAMES = {
blacklist: 'Blacklist',
threshold: 'Word frequency threshold',
};
export const VIEW_TYPE = 'word-frequency-view';