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
49 changes: 49 additions & 0 deletions src/components/CitationExporter/useCitationExporter.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { act } from '@testing-library/react';
import { describe, expect, test, vi } from 'vitest';

import { ExportApiFormatKey } from '@/api/export/types';
import { renderHook } from '@/test-utils';

import { useCitationExporter } from './useCitationExporter';

vi.mock('next/router', () => ({
useRouter: () => ({ pathname: '/', push: vi.fn(), asPath: '/', query: {}, beforePopState: vi.fn() }),
}));

const baseProps = {
records: ['2021APS..APRA01003G'],
format: ExportApiFormatKey.bibtex,
singleMode: false,
};

describe('useCitationExporter — prop ↔ machine sync', () => {
test('SET_FORMAT dispatched from UI persists and is not reverted by the prop-sync effect', () => {
const { result, rerender } = renderHook(() => useCitationExporter(baseProps));

expect(result.current.state.context.params.format).toBe(ExportApiFormatKey.bibtex);

act(() => {
result.current.dispatch({ type: 'SET_FORMAT', payload: ExportApiFormatKey.endnote });
});

expect(result.current.state.context.params.format).toBe(ExportApiFormatKey.endnote);

// Re-render with the same (unchanged) props. The prop-sync effect must not
// revert the user's choice back to the original `format` prop.
rerender();
expect(result.current.state.context.params.format).toBe(ExportApiFormatKey.endnote);
});

test('prop change still syncs into the machine', () => {
const { result, rerender } = renderHook(
({ format }: { format: ExportApiFormatKey }) => useCitationExporter({ ...baseProps, format }),
undefined,
{ initialProps: { format: ExportApiFormatKey.bibtex } },
);

expect(result.current.state.context.params.format).toBe(ExportApiFormatKey.bibtex);

rerender({ format: ExportApiFormatKey.ris });
expect(result.current.state.context.params.format).toBe(ExportApiFormatKey.ris);
});
});
14 changes: 8 additions & 6 deletions src/components/CitationExporter/useCitationExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,14 @@ export const useCitationExporter = ({
// trigger updates to machine state if incoming props change
useEffect(() => dispatch({ type: 'SET_SINGLEMODE', payload: singleMode }), [singleMode, dispatch]);

// watch for format changes
// One-way prop -> machine sync. Must depend only on the prop; adding the
// derived machine value (params.format) would cause the effect to re-fire
// after a user-initiated SET_FORMAT and immediately revert it.
useEffect(() => {
if (format !== params.format) {
dispatch({ type: 'SET_FORMAT', payload: format });
}
}, [format, params.format, dispatch]);
}, [format]); // eslint-disable-line react-hooks/exhaustive-deps
Comment on lines 88 to +92

// if we're in singleMode and format is changed, trigger a submit
useEffect(() => {
Expand All @@ -96,21 +98,21 @@ export const useCitationExporter = ({
}
}, [params.format, singleMode, dispatch]);

// watch for changes to records
// One-way prop -> machine sync. See note on the format effect above.
useEffect(() => {
// naively compare only the first record, this should be enough to determine
// there is a difference
if (records[0] !== state.context.records[0]) {
dispatch({ type: 'SET_RECORDS', payload: records });
}
}, [records, state.context.records, dispatch]);
}, [records]); // eslint-disable-line react-hooks/exhaustive-deps

// watch for changes to sort
// One-way prop -> machine sync. See note on the format effect above.
useEffect(() => {
if (sort !== params.sort) {
dispatch({ type: 'SET_SORT', payload: sort });
}
}, [sort, params.sort, dispatch]);
}, [sort]); // eslint-disable-line react-hooks/exhaustive-deps

// main result fetcher, this will not run unless we're in the 'fetching' state
const result = useGetExportCitation(params, {
Expand Down
Loading