From 09a8c31b24651c0c8274cc86fec7d703c21931b3 Mon Sep 17 00:00:00 2001 From: Rudy Mizrahi Celekli <47457359+rudycelekli@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:03:09 -0400 Subject: [PATCH] fix(jobdanmark-search): filter search by the administrative regions locations returns (#650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(jobdanmark-search): filter search by the administrative regions locations returns `locations` lists two kinds of region: landsdele such as Østjylland (category `region`) and the administrative regions such as Region Midtjylland (category `administrativeRegion`), and the search API filters each by its own type. `--region` always sent type `region`, so an administrative region - and SKILL.md's own `--region Midtjylland` example - returned a successful search with zero jobs. Add `--administrative-region`, sent as the `administrativeRegion` filter, map each locations category to its flag in SKILL.md and the README, and give `--region` examples that exist. Co-Authored-By: Claude Opus 5.5 * changelog: place the #650 entry under [Unreleased] Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 Co-authored-by: Mads Lorentzen --- .agents/skills/jobdanmark-search/SKILL.md | 5 +- .../skills/jobdanmark-search/cli/README.md | 5 +- .../cli/src/commands/search.ts | 11 ++- .../cli/tests/region-filter-cli.test.ts | 75 +++++++++++++++++++ CHANGELOG.md | 10 +++ 5 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 .agents/skills/jobdanmark-search/cli/tests/region-filter-cli.test.ts diff --git a/.agents/skills/jobdanmark-search/SKILL.md b/.agents/skills/jobdanmark-search/SKILL.md index 6163ebd7..9dde4caf 100644 --- a/.agents/skills/jobdanmark-search/SKILL.md +++ b/.agents/skills/jobdanmark-search/SKILL.md @@ -52,7 +52,8 @@ Key flags: - `--jobtitle-id ` — job title ID from `autocomplete` results - `--municipality ` — e.g. `Odense`, `København`, `Aarhus` - `--zip ` — zip code, e.g. `5000`, `8000`, `2100` -- `--region ` — region name, e.g. `Midtjylland`, `Sjælland` +- `--region ` — landsdel (`locations` category `region`), e.g. `Sjælland`, `Østjylland`, `Fyn` +- `--administrative-region ` — one of the five regions (`locations` category `administrativeRegion`), e.g. `Region Midtjylland` - `--job-type ` — comma-separated: `fuldtid`, `deltid`, `fleksjob`, `elev`, `studiejob`, `praktik` - `--page ` — page number (30 items per page, server-enforced) - `--limit ` — cap total results returned by CLI @@ -91,7 +92,7 @@ Use this to resolve search terms into precise job title IDs (`--jobtitle-id`) or bun run .agents/skills/jobdanmark-search/cli/src/cli.ts locations --query "" [--limit ] ``` -Returns matching municipalities, zip codes, and regions. Use `value` from results as `--municipality` or `--zip` in `search`. +Returns matching municipalities, zip codes, and regions. Pass an item's `value` to the `search` flag named by its `category`: `municipality` → `--municipality`, `zip` → `--zip`, `region` → `--region`, `administrativeRegion` → `--administrative-region`. A value under the wrong flag matches no jobs. --- diff --git a/.agents/skills/jobdanmark-search/cli/README.md b/.agents/skills/jobdanmark-search/cli/README.md index 65eb90ce..1ca50d0f 100644 --- a/.agents/skills/jobdanmark-search/cli/README.md +++ b/.agents/skills/jobdanmark-search/cli/README.md @@ -79,7 +79,8 @@ bun run src/cli.ts search [flags] | `--jobtitle-id` | number | — | Job title ID from `autocomplete` results | | `--municipality` | string | — | Municipality name, e.g. `Odense`, `København` | | `--zip` | string | — | Zip code, e.g. `5000` | -| `--region` | string | — | Region name | +| `--region` | string | — | Landsdel: a `locations` item with category `region`, e.g. `Sjælland`, `Østjylland` | +| `--administrative-region` | string | — | Administrative region: a `locations` item with category `administrativeRegion`, e.g. `Region Midtjylland` | | `--job-type` | string | — | Comma-separated job types: `fuldtid,deltid,fleksjob,elev,studiejob,praktik` | | `--page` | number | `1` | Page number (30 items per page, server-enforced) | | `--limit` | number | — | Cap total results returned by CLI (client-side) | @@ -420,7 +421,7 @@ bun run src/cli.ts locations --query "Sjælland" ] ``` -> **Note**: Returns `[]` when no locations match. The `value` field for municipalities is the display name (string); for zip codes it is the numeric string. Use `value` directly as `--municipality` or `--zip` in `search`. +> **Note**: Returns `[]` when no locations match. The `value` field for municipalities is the display name (string); for zip codes it is the numeric string. Pass `value` to the `search` flag matching its `category`: `--municipality`, `--zip`, `--region` (category `region`, a landsdel such as `Sjælland`) or `--administrative-region` (category `administrativeRegion`, such as `Region Midtjylland`). Under any other flag the value matches no jobs. --- diff --git a/.agents/skills/jobdanmark-search/cli/src/commands/search.ts b/.agents/skills/jobdanmark-search/cli/src/commands/search.ts index 7b4a4f73..838880a8 100644 --- a/.agents/skills/jobdanmark-search/cli/src/commands/search.ts +++ b/.agents/skills/jobdanmark-search/cli/src/commands/search.ts @@ -105,7 +105,10 @@ export const search = defineCommand({ description: "Zip code, e.g. 5000", }), region: option(z.string().optional(), { - description: "Region name", + description: "Landsdel from locations (category region), e.g. Sjælland, Østjylland", + }), + "administrative-region": option(z.string().optional(), { + description: "Administrative region from locations (category administrativeRegion), e.g. Region Midtjylland", }), "job-type": option(z.string().optional(), { description: "Comma-separated job types: fuldtid,deltid,fleksjob,elev,studiejob,praktik", @@ -143,6 +146,12 @@ export const search = defineCommand({ if (flags.region) { filters.push({ type: "region", value: flags.region, displayText: flags.region }) } + // `locations` returns two kinds of region, and the API filters each by its + // own type: a "region" filter holding "Region Midtjylland" matches no job. + if (flags["administrative-region"]) { + const value = flags["administrative-region"] + filters.push({ type: "administrativeRegion", value, displayText: value }) + } const jobTypes = flags["job-type"] ? flags["job-type"].split(",").map((t) => t.trim()).filter(Boolean) diff --git a/.agents/skills/jobdanmark-search/cli/tests/region-filter-cli.test.ts b/.agents/skills/jobdanmark-search/cli/tests/region-filter-cli.test.ts new file mode 100644 index 00000000..e319a9f8 --- /dev/null +++ b/.agents/skills/jobdanmark-search/cli/tests/region-filter-cli.test.ts @@ -0,0 +1,75 @@ +import { expect, test } from "bun:test"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +// Both region kinds exactly as GET /api/search/locations?q=jylland returns them. +const LOCATIONS = [ + { + title: "Landsdel", + items: [{ id: "region__218546", text: "Østjylland", value: "Østjylland", category: "region", slug: "oestjylland" }], + }, + { + title: "Region", + items: [{ + id: "administrativeRegion__389101", + text: "Region Midtjylland", + value: "Region Midtjylland", + category: "administrativeRegion", + slug: "region-midtjylland", + }], + }, +]; + +async function searchFilters(args: string[]) { + const bodies: unknown[] = []; + const server = Bun.serve({ + hostname: "127.0.0.1", + port: 0, + async fetch(request) { + bodies.push(await request.json()); + return Response.json({ items: [], currentPage: 1, totalItems: 0, itemsPrPage: 30, totalPages: 0 }); + }, + }); + const dir = mkdtempSync(join(tmpdir(), "jobdanmark-region-")); + const preload = join(dir, "fetch.ts"); + writeFileSync(preload, ` + const originalFetch = globalThis.fetch; + globalThis.fetch = (input, init) => { + const url = new URL(input instanceof Request ? input.url : String(input)); + if (url.protocol === "data:") return originalFetch(input, init); + if (url.origin !== "https://jobdanmark.dk" || url.pathname !== "/api/jobsearch/search/1") { + throw new Error("Unexpected search fixture request"); + } + return originalFetch(${JSON.stringify(server.url.origin)} + url.pathname, init); + }; + `); + try { + const proc = Bun.spawn([ + process.execPath, "run", "--preload", preload, + join(import.meta.dir, "../src/cli.ts"), "search", ...args, + ], { stdout: "pipe", stderr: "pipe" }); + const [stderr, exitCode] = await Promise.all([new Response(proc.stderr).text(), proc.exited]); + expect(stderr).toBe(""); + expect(exitCode).toBe(0); + expect(bodies).toHaveLength(1); + return (bodies[0] as { filters: Array<{ type: string; value: string; displayText: string }> }).filters; + } finally { + server.stop(true); + rmSync(dir, { recursive: true, force: true }); + } +} + +const item = (category: string) => LOCATIONS.flatMap((g) => g.items).find((i) => i.category === category)!; + +test("an administrativeRegion location is sent with the API's administrativeRegion filter type", async () => { + const { value } = item("administrativeRegion"); + const filters = await searchFilters(["--administrative-region", value]); + expect(filters).toEqual([{ type: "administrativeRegion", value, displayText: value }]); +}); + +test("a region (landsdel) location keeps the region filter type", async () => { + const { value } = item("region"); + const filters = await searchFilters(["--region", value]); + expect(filters).toEqual([{ type: "region", value, displayText: value }]); +}); diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cdb4a74..6ff8391b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -146,6 +146,16 @@ per-file diff commands. API's `occupations` parameter returns the 830 nurse ads for the same UUID. The new flag sends that parameter and accepts the full URI or the bare UUID; the docs stop pointing at the numeric flags. +- **`jobdanmark-search search` can filter by the administrative regions that `locations` returns** + (#650, `.agents/skills/jobdanmark-search/cli/src/commands/search.ts`, `tests/region-filter-cli.test.ts`, + `SKILL.md`, `cli/README.md`) - `locations` lists two kinds of region: landsdele such as `Østjylland` + (category `region`) and the five administrative regions such as `Region Midtjylland` (category + `administrativeRegion`), and the search API filters each by its own type. `--region` always sent + type `region`, so an administrative region - and SKILL.md's own example `--region Midtjylland` - came + back as a successful search with zero jobs. A new `--administrative-region` flag sends the + `administrativeRegion` filter (2,486 jobs for `Region Midtjylland`), and the docs map each `locations` + category to its flag and give `--region` examples that exist. + ## [1.7.3] - 2026-10-19 ### Added