mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-07-14 18:15:56 -04:00
- Replace root `eslint-plugin-lingui` jsPlugin with `@e18e/eslint-plugin`; move lingui rules into per-app `.oxlintrc.json` overrides for native and web
- Add `jsx-a11y`, `react-hooks-js` (native), and expanded lingui rule sets to per-app configs
- Add `oxc/no-barrel-file` warning at threshold 0 to root config
- Fix `e18e/prefer-url-canparse`: replace `try { new URL() } catch` with `URL.canParse()` in server-url screen and server lib
- Fix `e18e/prefer-timer-args`: pass callback args directly to `setTimeout` instead of wrapping in arrow functions (use-debounce, integration-card)
- Fix `e18e/prefer-static-regex`: hoist `/\/+$/` to module-level constant in server-url screen
- Fix `react-hooks-js/refs` and `react-hooks-js/set-state-in-effect`: convert `useRef` tracking patterns to `useState` + render-time derived updates in `use-server-connection`, `expandable-text`, and settings screen
- Fix `react-hooks-js/immutability`: extract stable palette sub-values before `useMemo` deps in title detail screen
- Apply `e18e` and other rule fixes across core, tmdb, web components, and i18n packages
125 lines
4.0 KiB
TypeScript
125 lines
4.0 KiB
TypeScript
import { beforeEach, describe, expect, test } from "vitest";
|
|
|
|
import { clearAllTables, insertUser } from "@sofa/test/db";
|
|
|
|
const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}T/;
|
|
|
|
import {
|
|
createOrUpdateIntegration,
|
|
deleteIntegration,
|
|
findIntegrationByToken,
|
|
listUserIntegrations,
|
|
regenerateToken,
|
|
} from "../src/integrations";
|
|
|
|
beforeEach(() => {
|
|
clearAllTables();
|
|
insertUser("user-1");
|
|
});
|
|
|
|
describe("createOrUpdateIntegration", () => {
|
|
test("creates a new webhook integration", () => {
|
|
const result = createOrUpdateIntegration("user-1", "plex");
|
|
expect(result.provider).toBe("plex");
|
|
expect(result.type).toBe("webhook");
|
|
expect(result.enabled).toBe(true);
|
|
expect(result.token).toHaveLength(64); // 32 bytes hex
|
|
});
|
|
|
|
test("creates a list integration for sonarr", () => {
|
|
const result = createOrUpdateIntegration("user-1", "sonarr");
|
|
expect(result.type).toBe("list");
|
|
});
|
|
|
|
test("creates a list integration for radarr", () => {
|
|
const result = createOrUpdateIntegration("user-1", "radarr");
|
|
expect(result.type).toBe("list");
|
|
});
|
|
|
|
test("returns existing integration without duplicating", () => {
|
|
const first = createOrUpdateIntegration("user-1", "plex");
|
|
const second = createOrUpdateIntegration("user-1", "plex");
|
|
expect(second.id).toBe(first.id);
|
|
expect(second.token).toBe(first.token);
|
|
});
|
|
|
|
test("updates enabled state on existing integration", () => {
|
|
createOrUpdateIntegration("user-1", "plex", true);
|
|
const updated = createOrUpdateIntegration("user-1", "plex", false);
|
|
expect(updated.enabled).toBe(false);
|
|
});
|
|
|
|
test("creates with enabled=false when specified", () => {
|
|
const result = createOrUpdateIntegration("user-1", "jellyfin", false);
|
|
expect(result.enabled).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("listUserIntegrations", () => {
|
|
test("returns empty list for user with no integrations", () => {
|
|
const result = listUserIntegrations("user-1");
|
|
expect(result.integrations).toHaveLength(0);
|
|
});
|
|
|
|
test("returns all integrations for user", () => {
|
|
createOrUpdateIntegration("user-1", "plex");
|
|
createOrUpdateIntegration("user-1", "jellyfin");
|
|
|
|
const result = listUserIntegrations("user-1");
|
|
expect(result.integrations).toHaveLength(2);
|
|
const providers = result.integrations.map((i) => i.provider).sort();
|
|
expect(providers).toEqual(["jellyfin", "plex"]);
|
|
});
|
|
|
|
test("does not return other users integrations", () => {
|
|
insertUser("user-2");
|
|
createOrUpdateIntegration("user-1", "plex");
|
|
createOrUpdateIntegration("user-2", "jellyfin");
|
|
|
|
const result = listUserIntegrations("user-1");
|
|
expect(result.integrations).toHaveLength(1);
|
|
expect(result.integrations[0].provider).toBe("plex");
|
|
});
|
|
|
|
test("serializes dates as ISO strings", () => {
|
|
createOrUpdateIntegration("user-1", "plex");
|
|
const result = listUserIntegrations("user-1");
|
|
expect(result.integrations[0].createdAt).toMatch(ISO_DATE_RE);
|
|
});
|
|
});
|
|
|
|
describe("deleteIntegration", () => {
|
|
test("removes an integration", () => {
|
|
createOrUpdateIntegration("user-1", "plex");
|
|
deleteIntegration("user-1", "plex");
|
|
|
|
const result = listUserIntegrations("user-1");
|
|
expect(result.integrations).toHaveLength(0);
|
|
});
|
|
|
|
test("does not throw for nonexistent integration", () => {
|
|
expect(() => deleteIntegration("user-1", "nonexistent")).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe("findIntegrationByToken", () => {
|
|
test("finds integration by token", () => {
|
|
const created = createOrUpdateIntegration("user-1", "plex");
|
|
const found = findIntegrationByToken(created.token);
|
|
expect(found?.id).toBe(created.id);
|
|
});
|
|
|
|
test("returns undefined for invalid token", () => {
|
|
expect(findIntegrationByToken("nonexistent")).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("regenerateToken", () => {
|
|
test("generates a new token for existing integration", () => {
|
|
const created = createOrUpdateIntegration("user-1", "plex");
|
|
const result = regenerateToken("user-1", "plex");
|
|
expect(result?.token).not.toBe(created.token);
|
|
expect(result?.token).toHaveLength(64);
|
|
});
|
|
});
|