wrolpi/app/src/components/MapSearchView.test.js
lrnselfreliance 63ddad69e8
app: api helpers report failure instead of returning an empty value (#736)
Six helpers turned a non-OK response into an empty value, so their
consumers rendered a server error as "nothing here":

* getConfigBackups -> {dates: []}: "No backups available for this
  config."  A thrown request also left "Loading backups..." forever.
* getInventoryBackups -> []: "No backups yet."
* getDownloaders -> {downloaders: []} on a throw, the error body on a
  non-OK response (which then crashed the .map): the RSS form's
  Downloader select sat empty.
* searchMap -> {results: []}: "No map locations found".
* getMapSearchStatus -> {indexed: [], missing: []}: "No maps are
  installed".
* flasherSearch -> [null, null], then `|| []`: "No .bin firmware
  found".

Invariants now enforced and tested:
* On a non-OK response each helper returns undefined; an empty value
  only ever comes from the server.
* Each consumer shows an error for a failed or thrown fetch and keeps
  its "none" message for a confirmed empty result.  The Downloader
  select is disabled and says it is loading or could not fetch.  A
  failed map status is unknown, never "no maps are installed".
* The map search tab loads from the first render, and a query shorter
  than the two characters the request needs now says so instead of
  "No map locations found".

Archive browsers and recent tags are left as they are: a failed fetch
there hides an optional picker or suggestion list without claiming
anything.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:47:32 -06:00

61 lines
2.3 KiB
JavaScript

import React from 'react';
import {render, screen} from '../test-utils';
import {MapSearchView} from './MapSearchView';
import {getMapSearchStatus, searchMap} from '../api';
// The map search tab says "No map locations found" only when the server searched and found none,
// and "No maps are installed" only when the server said so. A failed request is an error.
jest.mock('../api', () => ({
...jest.requireActual('../api'),
getMapSearchStatus: jest.fn(),
searchMap: jest.fn(),
}));
const NOT_FOUND = /No map locations found/;
const NO_MAPS = /No maps are installed/;
const FAILED = /Could not search the map/;
const renderAt = (q) => render(<MapSearchView/>, {query: {searchParams: new URLSearchParams({q})}});
beforeEach(() => {
getMapSearchStatus.mockReset();
searchMap.mockReset();
getMapSearchStatus.mockResolvedValue({indexed: ['utah'], missing: []});
});
test('found nothing: says so', async () => {
searchMap.mockResolvedValue({results: [], total: 0});
renderAt('camp');
expect(await screen.findByText(NOT_FOUND)).toBeInTheDocument();
});
test('a failed search shows an error, not "No map locations found"', async () => {
searchMap.mockResolvedValue(undefined);
renderAt('camp');
expect(await screen.findByText(FAILED)).toBeInTheDocument();
expect(screen.queryByText(NOT_FOUND)).not.toBeInTheDocument();
});
test('a failed status check does not claim no maps are installed', async () => {
getMapSearchStatus.mockResolvedValue(undefined);
searchMap.mockResolvedValue({results: [], total: 0});
renderAt('camp');
expect(await screen.findByText(NOT_FOUND)).toBeInTheDocument();
expect(screen.queryByText(NO_MAPS)).not.toBeInTheDocument();
});
test('a thrown status check does not claim no maps are installed', async () => {
getMapSearchStatus.mockRejectedValue(new Error('down'));
searchMap.mockResolvedValue({results: [], total: 0});
renderAt('camp');
expect(await screen.findByText(NOT_FOUND)).toBeInTheDocument();
expect(screen.queryByText(NO_MAPS)).not.toBeInTheDocument();
});
test('the server saying no maps are installed is shown', async () => {
getMapSearchStatus.mockResolvedValue({indexed: [], missing: []});
searchMap.mockResolvedValue({results: [], total: 0});
renderAt('camp');
expect(await screen.findByText(NO_MAPS)).toBeInTheDocument();
});