app: a download frequency of "Once" no longer blocks submission

useForm treated any falsy value as a missing required field.  "Once" is
frequency 0, so the Channel/Playlist, RSS, and Zim download forms never
became ready and the Download button stayed disabled.  Only null,
undefined, '', false, and NaN count as missing now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Roland 2026-10-09 14:15:50 -06:00
parent c8d5765ea3
commit 298988503e
No known key found for this signature in database
GPG key ID: 1BA620CE6C9A4680
3 changed files with 37 additions and 1 deletions

View file

@ -127,6 +127,15 @@ describe('<ChannelDownloadForm/>', () => {
shouldBeInvalid('#url_input');
});
it('can be submitted with a frequency of Once', () => {
cy.get('#url_input').type('https://example.com/playlist').wait(500);
cy.get('#frequency_select').click();
cy.contains('[role="option"]:visible', 'Once').should('be.visible').click({force: true});
cy.get('#frequency_select').should('have.value', 'Once');
cy.get('#download_form_download_button').should('not.be.disabled');
});
it('can choose different options', () => {
/*
* `#download_frequency_selector` and `.item` named the old dropdown and its menu rows.

View file

@ -67,7 +67,11 @@ export function useForm({
setReady(false);
return
}
const missingValues = Object.keys(memoizedRequires).filter(i => !_.get(formData, i));
// 0 is a real value (a download frequency of "Once"), only empty values are missing.
const missingValues = Object.keys(memoizedRequires).filter(i => {
const value = _.get(formData, i);
return value === null || value === undefined || value === '' || value === false || Number.isNaN(value);
});
if (missingValues.length > 0) {
console.debug(`Form invalid because it is missing required value: ${missingValues[0]}`);
setReady(false);

View file

@ -727,6 +727,29 @@ describe('useForm', () => {
});
});
it('zero satisfies a required field', async () => {
// A download frequency of 0 means "Once".
const {result} = renderHook(() => useForm({
defaultFormData: {frequency: null},
submitter: jest.fn(),
}));
act(() => {
result.current.getCustomProps({name: 'frequency', required: true});
});
await waitFor(() => {
expect(result.current.ready).toBe(false);
});
act(() => {
result.current.setValue('frequency', 0);
});
await waitFor(() => {
expect(result.current.formData.frequency).toBe(0);
expect(result.current.ready).toBe(true);
});
});
it('addRequires marks field as required', async () => {
const {result} = renderHook(() => useForm({
defaultFormData: {field: ''},