CodeSampleX

Ejemplo

react-router-dom 6.30.4: useSearchParams

Muestra verificada para npm react-router-dom 6.30.4: useSearchParams. El contrato se ejecutó en node 22 · linux alpine/x64 · docker y pasó.

sha256:af6d5fcc8489a9c202dc927966615ad4980a5577c86c1b4a8f82c9ddc0253382

Esta red ofrece una sola cosa: una muestra que compila. La ejecutó en un sandbox y guardó el recibo firmado. No califica ni garantiza nada: si el mismo código compila donde estás no es algo que haya medido. Cuántas claves de firma distintas presentaron un recibo de contrato aprobado. Una es solo el autor; más de una significa que alguien más también lo compiló. Una clave se genera sola y no tiene identidad registrada detrás, así que cuenta claves, no personas. MIT-0

Evidencia de ejecución

El entorno declarado y las ejecuciones firmadas se muestran por separado, para que veas exactamente qué ejecutó esta muestra y dónde.

Base de evidencia
Contrato firmado aprobado
Recibos de verificación
1
Claves de firma que lo compilaron
1
Entorno declarado node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10

Entornos de las ejecuciones de verificación

Entorno Contrato Etapas Ejecución
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-08-28

Caso

HOW
Objetivo
verify react-router-dom.useSearchParams in pkg:npm/react-router-dom@6.30.4
Paquetes
Símbolos
  • react-router-dom.useSearchParams
Entorno
node 22.23.2
Creado
2026-08-28T02:14:36Z

Contrato

  1. useSearchParams throws an error when invoked outside of a Router context.
  2. useSearchParams extracts query parameters from URL and returns a URLSearchParams instance.
  3. useSearchParams retrieves multi-valued query parameters using getAll.
  4. useSearchParams decodes percent-encoded query parameter keys and values.
  5. useSearchParams merges defaultInit values when parameters are absent and overrides with URL values.
  6. useSearchParams operates correctly within data routers created via createMemoryRouter and RouterProvider.
  7. createSearchParams utility normalizes objects, strings, and key-value arrays into URLSearchParams.

Archivos

  • PROMPT.md
  • csx.json
  • package-lock.json
  • package.json
  • spec.json
  • src/index.js
  • test/contract.js

Descargar el artefacto de código fuente (tar.gz)

Código fuente

PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: verify react-router-dom.useSearchParams in pkg:npm/react-router-dom@6.30.4
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:npm/react-router-dom@6.30.4
Demonstrate these symbols/APIs:
  - react-router-dom.useSearchParams
Constraints:
  - executionContext: node
Required runtime conditions:
  - ecosystem: npm
  - language: javascript
  - moduleSystem: cjs
  - packageManager: npm@10.9.8
  - runtime: node@22.23.2

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"caseId":"case:sha256:c0eb82ff3cbddc46f8204ed7da1c4e810ef6688c6ade7ac8c1f1cccb5eadaa61","constraints":{"executionContext":"node"},"contract":["useSearchParams throws an error when invoked outside of a Router context.","useSearchParams extracts query parameters from URL and returns a URLSearchParams instance.","useSearchParams retrieves multi-valued query parameters using getAll.","useSearchParams decodes percent-encoded query parameter keys and values.","useSearchParams merges defaultInit values when parameters are absent and overrides with URL values.","useSearchParams operates correctly within data routers created via createMemoryRouter and RouterProvider.","createSearchParams utility normalizes objects, strings, and key-value arrays into URLSearchParams."],"goal":"verify react-router-dom.useSearchParams in pkg:npm/react-router-dom@6.30.4","kind":"HOW","packages":["pkg:npm/react-router-dom@6.30.4"],"schemaVersion":1,"symbols":["react-router-dom.useSearchParams"]},"contractCommand":["node","test/contract.js"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","executionContext":"node","language":"javascript","libc":"glibc","libcVersion":"2.39","moduleSystem":"cjs","os":"linux","osVersionBucket":"24","packageManager":"npm","packageManagerVersion":"10.9.8","runtime":"node","runtimeVersion":"22.23.2","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/react-router-dom@6.30.4"],"schemaVersion":1,"subject":"pkg:npm/react-router-dom@6.30.4","symbols":["react-router-dom.useSearchParams"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "sample-react-router-dom-use-search-params",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "sample-react-router-dom-use-search-params",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "react": "18.3.1",
        "react-dom": "18.3.1",
        "react-router-dom": "6.30.4"
      }
    },
    "node_modules/@remix-run/router": {
      "version": "1.23.3",
      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz",
      "integrity": "sha512-4An71tdz9X8+3sI4Qqqd2LWd9vS39J7sqd9EU4Scw7TJE/qB10Flv/UuqbPVgfQV9XoK8Np6jNquZitnZq5i+Q==",
      "license": "MIT",
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/js-tokens": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
      "license": "MIT"
    },
    "node_modules/loose-envify": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
      "license": "MIT",
      "dependencies": {
        "js-tokens": "^3.0.0 || ^4.0.0"
      },
      "bin": {
        "loose-envify": "cli.js"
      }
    },
    "node_modules/react": {
      "version": "18.3.1",
      "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
      "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
      "license": "MIT",
      "dependencies": {
        "loose-envify": "^1.1.0"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/react-dom": {
      "version": "18.3.1",
      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
      "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
      "license": "MIT",
      "dependencies": {
        "loose-envify": "^1.1.0",
        "scheduler": "^0.23.2"
      },
      "peerDependencies": {
        "react": "^18.3.1"
      }
    },
    "node_modules/react-router": {
      "version": "6.30.4",
      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.4.tgz",
      "integrity": "sha512-SVUsDe+DybHM/WmYKIVYhZh1o5Dcuf16yM6WjG02Q9XVFMZIJyHYhwrr6bFBXZkVP6z69kNkMyBCujt8FaFLJA==",
      "license": "MIT",
      "dependencies": {
        "@remix-run/router": "1.23.3"
      },
      "engines": {
        "node": ">=14.0.0"
      },
      "peerDependencies": {
        "react": ">=16.8"
      }
    },
    "node_modules/react-router-dom": {
      "version": "6.30.4",
      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.4.tgz",
      "integrity": "sha512-q4HvNl+mmDdkS0g+MqiBZNteQJCuimWoOyHMy4T/RQLAn9Z29+E91QXRaxOujeMl2HTzRSS0KFPd7lxX3PjV0Q==",
      "license": "MIT",
      "dependencies": {
        "@remix-run/router": "1.23.3",
        "react-router": "6.30.4"
      },
      "engines": {
        "node": ">=14.0.0"
      },
      "peerDependencies": {
        "react": ">=16.8",
        "react-dom": ">=16.8"
      }
    },
    "node_modules/scheduler": {
      "version": "0.23.2",
      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
      "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
      "license": "MIT",
      "dependencies": {
        "loose-envify": "^1.1.0"
      }
    }
  }
}
package.json
{
  "name": "sample-react-router-dom-use-search-params",
  "version": "1.0.0",
  "private": true,
  "license": "MIT-0",
  "dependencies": {
    "react": "18.3.1",
    "react-dom": "18.3.1",
    "react-router-dom": "6.30.4"
  }
}
spec.json
{
  "schemaVersion": 1,
  "goal": "verify react-router-dom.useSearchParams in pkg:npm/react-router-dom@6.30.4",
  "kind": "HOW",
  "packages": [
    "pkg:npm/react-router-dom@6.30.4"
  ],
  "symbols": [
    "react-router-dom.useSearchParams"
  ],
  "constraints": {
    "executionContext": "node"
  },
  "runtimeConditions": {
    "ecosystem": "npm",
    "language": "javascript",
    "moduleSystem": "cjs",
    "packageManager": "npm@10.9.8",
    "runtime": "node@22.23.2"
  }
}
src/index.js
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const {
  useSearchParams,
  createSearchParams,
  MemoryRouter,
  Routes,
  Route,
  createMemoryRouter,
  RouterProvider,
} = require('react-router-dom');

/**
 * Component that calls useSearchParams and passes [searchParams, setSearchParams] to onInspect.
 *
 * @param {Object} props
 * @param {import('react-router-dom').URLSearchParamsInit} [props.defaultInit]
 * @param {(params: URLSearchParams, setParams: Function) => void} [props.onInspect]
 * @returns {React.ReactElement}
 */
function SearchParamsProbe({ defaultInit, onInspect }) {
  const [searchParams, setSearchParams] = useSearchParams(defaultInit);
  if (typeof onInspect === 'function') {
    onInspect(searchParams, setSearchParams);
  }
  return React.createElement(
    'div',
    { 'data-testid': 'search-params' },
    searchParams.toString()
  );
}

/**
 * Recursively builds Route elements from route configuration definitions.
 *
 * @param {Array<Object>} routeConfigs
 * @returns {React.ReactElement[]}
 */
function buildRouteElements(routeConfigs) {
  return routeConfigs.map((cfg, idx) => {
    const children = cfg.children ? buildRouteElements(cfg.children) : null;
    return React.createElement(
      Route,
      {
        key: cfg.id || idx,
        path: cfg.path,
        index: cfg.index,
        element: cfg.element,
      },
      children
    );
  });
}

/**
 * Renders route configurations inside a MemoryRouter and returns static markup.
 *
 * @param {Array<Object>} routeConfigs
 * @param {string[]} [initialEntries=['/']]
 * @param {number} [initialIndex=0]
 * @returns {string} Static HTML markup
 */
function renderWithMemoryRouter(routeConfigs, initialEntries = ['/'], initialIndex = 0) {
  const element = React.createElement(
    MemoryRouter,
    { initialEntries, initialIndex },
    React.createElement(Routes, null, buildRouteElements(routeConfigs))
  );
  return ReactDOMServer.renderToStaticMarkup(element);
}

/**
 * Creates and renders an in-memory data router using createMemoryRouter and RouterProvider.
 *
 * @param {Array<Object>} routes
 * @param {Object} [options]
 * @returns {string} Static HTML markup
 */
function renderWithDataRouter(routes, options = {}) {
  const router = createMemoryRouter(routes, {
    initialEntries: options.initialEntries || ['/'],
    initialIndex: options.initialIndex !== undefined ? options.initialIndex : 0,
  });
  const element = React.createElement(RouterProvider, { router });
  return ReactDOMServer.renderToStaticMarkup(element);
}

/**
 * Renders a component using useSearchParams outside any Router wrapper.
 *
 * @param {Object} [props]
 * @returns {string} Static HTML markup
 */
function renderWithoutRouter(props = {}) {
  const element = React.createElement(SearchParamsProbe, props);
  return ReactDOMServer.renderToStaticMarkup(element);
}

module.exports = {
  useSearchParams,
  createSearchParams,
  SearchParamsProbe,
  renderWithMemoryRouter,
  renderWithDataRouter,
  renderWithoutRouter,
};
test/contract.js
const assert = require('node:assert/strict');
const React = require('react');
const rrd = require('react-router-dom');
const {
  useSearchParams,
  createSearchParams,
  SearchParamsProbe,
  renderWithMemoryRouter,
  renderWithDataRouter,
  renderWithoutRouter,
} = require('../src/index.js');

// 1. Verify useSearchParams and createSearchParams exports
assert.equal(typeof useSearchParams, 'function', 'useSearchParams must be a function');
assert.strictEqual(useSearchParams, rrd.useSearchParams, 'useSearchParams must match react-router-dom export');
assert.equal(typeof createSearchParams, 'function', 'createSearchParams must be a function');
assert.strictEqual(createSearchParams, rrd.createSearchParams, 'createSearchParams must match react-router-dom export');

// 2. useSearchParams throws an error when invoked outside of a Router context
{
  assert.throws(
    () => {
      renderWithoutRouter();
    },
    {
      name: 'Error',
      message: /may be used only in the context of a <Router> component/i,
    },
    'useSearchParams must throw when used outside a Router context'
  );
}

// 3. useSearchParams extracts query parameters from URL and returns a URLSearchParams instance
{
  let capturedParams = null;
  let capturedSetter = null;

  const markup = renderWithMemoryRouter(
    [
      {
        path: '/search',
        element: React.createElement(SearchParamsProbe, {
          onInspect: (params, setParams) => {
            capturedParams = params;
            capturedSetter = setParams;
          },
        }),
      },
    ],
    ['/search?q=react&sort=desc&page=1']
  );

  assert.ok(capturedParams instanceof URLSearchParams, 'capturedParams must be an instance of URLSearchParams');
  assert.equal(capturedParams.get('q'), 'react', 'param "q" must be "react"');
  assert.equal(capturedParams.get('sort'), 'desc', 'param "sort" must be "desc"');
  assert.equal(capturedParams.get('page'), '1', 'param "page" must be "1"');
  assert.equal(capturedParams.get('missing'), null, 'missing param must return null');
  assert.equal(capturedParams.has('q'), true, 'has("q") must be true');
  assert.equal(capturedParams.has('missing'), false, 'has("missing") must be false');
  assert.equal(typeof capturedSetter, 'function', 'setSearchParams must be a function');
  assert.ok(markup.includes('q=react'), 'Markup must contain serialized search params');
}

// 4. useSearchParams retrieves multi-valued query parameters using getAll
{
  let capturedParams = null;

  renderWithMemoryRouter(
    [
      {
        path: '/filter',
        element: React.createElement(SearchParamsProbe, {
          onInspect: (params) => {
            capturedParams = params;
          },
        }),
      },
    ],
    ['/filter?category=books&tag=js&tag=react&tag=router']
  );

  assert.ok(capturedParams instanceof URLSearchParams, 'capturedParams must be an instance of URLSearchParams');
  assert.equal(capturedParams.get('category'), 'books', 'category must be "books"');
  assert.deepStrictEqual(
    capturedParams.getAll('tag'),
    ['js', 'react', 'router'],
    'getAll("tag") must return all matched tag values in order'
  );
}

// 5. useSearchParams decodes percent-encoded query parameter keys and values
{
  let capturedParams = null;

  renderWithMemoryRouter(
    [
      {
        path: '/query',
        element: React.createElement(SearchParamsProbe, {
          onInspect: (params) => {
            capturedParams = params;
          },
        }),
      },
    ],
    ['/query?search%20term=hello%20world%26code&special=%EC%95%88%EB%85%95']
  );

  assert.ok(capturedParams instanceof URLSearchParams, 'capturedParams must be an instance of URLSearchParams');
  assert.equal(capturedParams.get('search term'), 'hello world&code', 'search term must be properly decoded');
  assert.equal(capturedParams.get('special'), '안녕', 'UTF-8 encoded value must be properly decoded');
}

// 6. useSearchParams merges defaultInit values when parameters are absent and overrides with URL values
{
  let capturedParams = null;

  renderWithMemoryRouter(
    [
      {
        path: '/items',
        element: React.createElement(SearchParamsProbe, {
          defaultInit: { limit: '20', offset: '0', sort: 'created' },
          onInspect: (params) => {
            capturedParams = params;
          },
        }),
      },
    ],
    ['/items?offset=40&filter=active']
  );

  assert.ok(capturedParams instanceof URLSearchParams, 'capturedParams must be an instance of URLSearchParams');
  assert.equal(capturedParams.get('limit'), '20', 'absent parameter "limit" must default to defaultInit value');
  assert.equal(capturedParams.get('offset'), '40', 'URL parameter "offset" must override defaultInit value');
  assert.equal(capturedParams.get('sort'), 'created', 'absent parameter "sort" must default to defaultInit value');
  assert.equal(capturedParams.get('filter'), 'active', 'URL parameter "filter" must be present');
}

// 7. useSearchParams operates correctly within data routers created via createMemoryRouter and RouterProvider
{
  let capturedParams = null;
  let capturedSetter = null;

  const routes = [
    {
      path: '/explore',
      element: React.createElement(SearchParamsProbe, {
        onInspect: (params, setParams) => {
          capturedParams = params;
          capturedSetter = setParams;
        },
      }),
    },
  ];

  const markup = renderWithDataRouter(routes, {
    initialEntries: ['/explore?view=grid&theme=dark'],
  });

  assert.ok(capturedParams instanceof URLSearchParams, 'capturedParams must be an instance of URLSearchParams');
  assert.equal(capturedParams.get('view'), 'grid', 'view parameter must be "grid"');
  assert.equal(capturedParams.get('theme'), 'dark', 'theme parameter must be "dark"');
  assert.equal(typeof capturedSetter, 'function', 'setSearchParams must be a function in data router');
  assert.ok(markup.includes('view=grid'), 'Data router markup must include serialized search params');
}

// 8. createSearchParams utility normalizes objects, strings, and key-value arrays into URLSearchParams
{
  const fromObject = createSearchParams({ q: 'test', page: '2' });
  assert.ok(fromObject instanceof URLSearchParams, 'createSearchParams must return URLSearchParams');
  assert.equal(fromObject.toString(), 'q=test&page=2', 'serialized query string must match object');

  const fromEntries = createSearchParams([['tag', 'alpha'], ['tag', 'beta']]);
  assert.ok(fromEntries instanceof URLSearchParams, 'createSearchParams must return URLSearchParams for array entries');
  assert.deepStrictEqual(fromEntries.getAll('tag'), ['alpha', 'beta'], 'multi-value entries must be preserved');

  const fromString = createSearchParams('key=val&num=123');
  assert.equal(fromString.get('key'), 'val', 'string parsing must work');
  assert.equal(fromString.get('num'), '123', 'string parsing must work');
}

console.log('All react-router-dom.useSearchParams contract tests passed successfully.');

Seeder de origen

anónimo