Files
Tautvydas Derzinskas 2591714c0c feat: add Thangs provider
Imports Thangs models, likes and collections, and syncs them. Metadata is
public; files need the user's own sign-in, which Thingport Grab sends and
Thingport renews from the refresh token. Paid models download once owned;
print-only ones are refused before any download. Free accounts' daily
download limit stops a batch and defers the rest of a sync to its next check.
2026-10-19 23:36:07 +02:00

70 lines
2.5 KiB
TypeScript

import type { Server } from "node:http";
import { Test } from "supertest";
import { vi } from "vitest";
// supertest's request(app) listens on port 0 on every interface, then connects to 127.0.0.1 on the
// port it got. On macOS a wildcard bind succeeds even when another program already holds that port
// on 127.0.0.1 alone (VS Code helpers and limactl do), and that program takes the connection: the
// test then gets someone else's reply -- "Parse Error: Expected HTTP/", or a body without the field
// it expects -- in whichever test happens to draw the port.
//
// Binding to 127.0.0.1 itself means the port it's given is free there. That bind is asynchronous,
// though, and supertest reads the port the moment the request is built, so the bind waits until
// the request is sent and the port is filled into its URL then.
const PLACEHOLDER = "127.0.0.1:0";
type DeferredTest = InstanceType<typeof Test> & {
url: string;
_server?: Server;
unboundApp?: Server;
};
const proto = Test.prototype as unknown as {
serverAddress(this: DeferredTest, app: Server, path: string): string;
end(this: DeferredTest, fn?: (err: unknown, res: unknown) => void): DeferredTest;
};
const { serverAddress, end } = proto;
proto.serverAddress = function (app, path) {
if (app.address()) return serverAddress.call(this, app, path);
this.unboundApp = app;
return `http://${PLACEHOLDER}${path}`;
};
proto.end = function (fn) {
const app = this.unboundApp;
if (!app) return end.call(this, fn);
this.unboundApp = undefined;
app.once("error", (err) => fn?.(err, undefined));
app.listen(0, "127.0.0.1", () => {
const { port } = app.address() as { port: number };
// supertest's own field: it closes this server once the response is in.
// eslint-disable-next-line no-underscore-dangle
this._server = app;
this.url = this.url.replace(PLACEHOLDER, `127.0.0.1:${port}`);
end.call(this, fn);
});
return this;
};
// Tests mock global.fetch; send browserFetch through it too, read at call time so each test's mock applies.
vi.mock("../src/utils/browserFetch", async (importOriginal) => ({
...(await importOriginal<typeof import("../src/utils/browserFetch")>()),
browserFetch: (
url: string,
{
method,
body,
headers,
signal,
redirect,
}: {
method?: string;
body?: string;
headers?: Record<string, string>;
signal?: AbortSignal;
redirect?: RequestRedirect;
},
) => fetch(url, { method, body, headers, signal, redirect }),
}));