Ensure forwardCredentials is included when exporting servers as CSV

This commit is contained in:
Alejandro Celaya 2025-04-20 12:45:33 +02:00
parent 1467c8e416
commit 4895cbb9dc
3 changed files with 48 additions and 27 deletions

View File

@ -45,4 +45,12 @@ export const isNotFoundServer = (server: SelectedServer): server is NotFoundServ
export const getServerId = (server: SelectedServer) => (isServerWithId(server) ? server.id : '');
export const serverWithIdToServerData = ({ name, url, apiKey }: ServerWithId): ServerData => ({ name, url, apiKey });
/**
* Expose values that represent provided server, in a way that can be serialized in JSON or CSV strings.
*/
export const serializeServer = ({ name, url, apiKey, forwardCredentials }: ServerData): Record<string, string> => ({
name,
url,
apiKey,
forwardCredentials: forwardCredentials ? 'true' : 'false',
});

View File

@ -2,24 +2,27 @@ import type { JsonToCsv } from '../../utils/helpers/csvjson';
import { saveCsv } from '../../utils/helpers/files';
import type { LocalStorage } from '../../utils/services/LocalStorage';
import type { ServersMap } from '../data';
import { serverWithIdToServerData } from '../data';
import { serializeServer } from '../data';
const SERVERS_FILENAME = 'shlink-servers.csv';
export class ServersExporter {
public constructor(
private readonly storage: LocalStorage,
private readonly window: Window,
private readonly jsonToCsv: JsonToCsv,
) {}
readonly #storage: LocalStorage;
readonly #window: Window;
readonly #jsonToCsv: JsonToCsv;
public constructor(storage: LocalStorage, window: Window, jsonToCsv: JsonToCsv) {
this.#storage = storage;
this.#window = window;
this.#jsonToCsv = jsonToCsv;
}
public readonly exportServers = async () => {
const servers = Object.values(this.storage.get<ServersMap>('servers') ?? {}).map(serverWithIdToServerData);
const servers = Object.values(this.#storage.get<ServersMap>('servers') ?? {}).map(serializeServer);
try {
const csv = this.jsonToCsv(servers);
saveCsv(this.window, csv, SERVERS_FILENAME);
const csv = this.#jsonToCsv(servers);
saveCsv(this.#window, csv, SERVERS_FILENAME);
} catch (e) {
// FIXME Handle error
console.error(e);

View File

@ -1,27 +1,35 @@
import { fromPartial } from '@total-typescript/shoehorn';
import type { ServersMap } from '../../../src/servers/data';
import { serializeServer } from '../../../src/servers/data';
import { ServersExporter } from '../../../src/servers/services/ServersExporter';
import type { LocalStorage } from '../../../src/utils/services/LocalStorage';
import { appendChild, removeChild, windowMock } from '../../__mocks__/Window.mock';
describe('ServersExporter', () => {
const servers: ServersMap = {
abc123: {
id: 'abc123',
name: 'foo',
url: 'https://foo.com',
apiKey: 'foo_api_key',
autoConnect: true,
},
def456: {
id: 'def456',
name: 'bar',
url: 'https://bar.com',
apiKey: 'bar_api_key',
forwardCredentials: true,
autoConnect: false,
},
};
const storageMock = fromPartial<LocalStorage>({
get: vi.fn(() => ({
abc123: {
id: 'abc123',
name: 'foo',
autoConnect: true,
},
def456: {
id: 'def456',
name: 'bar',
autoConnect: false,
},
} as any)),
get: vi.fn(() => servers as any),
});
const erroneousToCsv = vi.fn(() => {
throw new Error('');
});
const createCsvjsonMock = (throwError = false) => (throwError ? erroneousToCsv : vi.fn(() => ''));
const createJsonToCsvMock = (throwError = false) => (throwError ? erroneousToCsv : vi.fn(() => ''));
describe('exportServers', () => {
const error = vi.fn();
@ -34,8 +42,8 @@ describe('ServersExporter', () => {
});
it('logs an error if something fails', () => {
const csvjsonMock = createCsvjsonMock(true);
const exporter = new ServersExporter(storageMock, windowMock, csvjsonMock);
const jsonToCsvMock = createJsonToCsvMock(true);
const exporter = new ServersExporter(storageMock, windowMock, jsonToCsvMock);
exporter.exportServers();
@ -44,7 +52,8 @@ describe('ServersExporter', () => {
});
it('makes use of download link API', () => {
const exporter = new ServersExporter(storageMock, windowMock, createCsvjsonMock());
const jsonToCsvMock = createJsonToCsvMock();
const exporter = new ServersExporter(storageMock, windowMock, jsonToCsvMock);
const { document: { createElement } } = windowMock;
exporter.exportServers();
@ -53,6 +62,7 @@ describe('ServersExporter', () => {
expect(createElement).toHaveBeenCalledTimes(1);
expect(appendChild).toHaveBeenCalledTimes(1);
expect(removeChild).toHaveBeenCalledTimes(1);
expect(jsonToCsvMock).toHaveBeenCalledWith(Object.values(servers).map(serializeServer));
});
});
});