Exemplo
react-router-dom 6.30.4: useParams
Amostra verificada para npm react-router-dom 6.30.4: useParams. O contrato rodou em node 22 · linux alpine/x64 · docker e passou.
sha256:35a258cadebde80755896b02f4bb26dd9b40ebe9003971b5765e66e56a0284f1
Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu.
Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas.
MIT-0
Evidência de execução
O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.
- Base da evidência
- Contrato assinado aprovado
- Recibos de verificação
- 1
- Chaves de assinatura que o compilaram
- 1
Ambiente declarado
node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10
Ambientes das execuções de verificação
| Ambiente | Contrato | Etapas | Execução |
|---|---|---|---|
| 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-25 |
Caso
HOW- Objetivo
- verify react-router-dom.useParams in pkg:npm/react-router-dom@6.30.4
- Pacotes
- Símbolos
-
- react-router-dom.useParams
- Ambiente
- node 22.23.2
- Criado
- 2026-08-25T12:37:12Z
Contrato
- useParams returns an empty object when invoked outside of a Router context.
- useParams extracts single named dynamic parameter from the matched route.
- useParams extracts and merges parameters across nested route layouts.
- useParams decodes percent-encoded URL values in route parameters.
- useParams handles optional parameter segments when omitted and when supplied.
- useParams captures catch-all wildcard splat parameter via asterisk route.
- useParams resolves parameters correctly within data routers created via createMemoryRouter and RouterProvider.
Arquivos
- PROMPT.md
- csx.json
- package-lock.json
- package.json
- spec.json
- src/index.js
- test/contract.js
Código-fonte
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.useParams 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.useParams
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.
{"case":{"caseId":"case:sha256:96276875144026a9f83915ba4fed76ebb6a6e83b8b5cfc31fdc07af2175442ee","constraints":{"executionContext":"node"},"contract":["useParams returns an empty object when invoked outside of a Router context.","useParams extracts single named dynamic parameter from the matched route.","useParams extracts and merges parameters across nested route layouts.","useParams decodes percent-encoded URL values in route parameters.","useParams handles optional parameter segments when omitted and when supplied.","useParams captures catch-all wildcard splat parameter via asterisk route.","useParams resolves parameters correctly within data routers created via createMemoryRouter and RouterProvider."],"goal":"verify react-router-dom.useParams 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.useParams"]},"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.useParams"],"verifierAdapter":"node-typescript@1"}
{
"name": "sample-react-router-dom-use-params",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sample-react-router-dom-use-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"
}
}
}
}
{
"name": "sample-react-router-dom-use-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"
}
}
{
"schemaVersion": 1,
"goal": "verify react-router-dom.useParams in pkg:npm/react-router-dom@6.30.4",
"kind": "HOW",
"packages": [
"pkg:npm/react-router-dom@6.30.4"
],
"symbols": [
"react-router-dom.useParams"
],
"constraints": {
"executionContext": "node"
},
"runtimeConditions": {
"ecosystem": "npm",
"language": "javascript",
"moduleSystem": "cjs",
"packageManager": "npm@10.9.8",
"runtime": "node@22.23.2"
}
}
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const {
useParams,
MemoryRouter,
Routes,
Route,
Outlet,
createMemoryRouter,
RouterProvider,
} = require('react-router-dom');
/**
* Component that calls useParams and passes the returned params object to onInspect callback.
*
* @param {Object} props
* @param {(params: Record<string, string | undefined>) => void} [props.onInspect]
* @returns {React.ReactElement}
*/
function ParamsProbe({ onInspect }) {
const params = useParams();
if (typeof onInspect === 'function') {
onInspect(params);
}
return React.createElement('div', { 'data-testid': 'params' }, JSON.stringify(params));
}
/**
* Layout component that renders an Outlet for nested routes while capturing params.
*
* @param {Object} props
* @param {(params: Record<string, string | undefined>) => void} [props.onInspect]
* @returns {React.ReactElement}
*/
function LayoutWithProbe({ onInspect }) {
const params = useParams();
if (typeof onInspect === 'function') {
onInspect(params);
}
return React.createElement(
'div',
{ 'data-layout-params': JSON.stringify(params) },
React.createElement(Outlet)
);
}
/**
* 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 useParams outside any Router wrapper.
*
* @param {(params: Record<string, string | undefined>) => void} [onInspect]
* @returns {string} Static HTML markup
*/
function renderWithoutRouter(onInspect) {
const element = React.createElement(ParamsProbe, { onInspect });
return ReactDOMServer.renderToStaticMarkup(element);
}
module.exports = {
useParams,
ParamsProbe,
LayoutWithProbe,
renderWithMemoryRouter,
renderWithDataRouter,
renderWithoutRouter,
};
const assert = require('node:assert/strict');
const React = require('react');
const rrd = require('react-router-dom');
const {
useParams,
ParamsProbe,
LayoutWithProbe,
renderWithMemoryRouter,
renderWithDataRouter,
renderWithoutRouter,
} = require('../src/index.js');
// 1. Verify useParams export
assert.equal(typeof useParams, 'function', 'useParams must be a function');
assert.strictEqual(useParams, rrd.useParams, 'useParams must match react-router-dom export');
// 2. useParams returns an empty object when invoked outside of a Router context
{
let inspected = null;
const markup = renderWithoutRouter((p) => {
inspected = p;
});
assert.ok(markup.includes('{}'), 'Markup outside Router must render empty params object');
assert.deepStrictEqual(inspected, {}, 'useParams outside Router must return an empty object');
}
// 3. useParams extracts single named dynamic parameter from the matched route
{
let captured = null;
const markup = renderWithMemoryRouter(
[
{
path: '/users/:userId',
element: React.createElement(ParamsProbe, {
onInspect: (p) => {
captured = p;
},
}),
},
],
['/users/usr_42']
);
assert.ok(markup.includes('usr_42'), 'Markup must contain user ID');
assert.deepStrictEqual(captured, { userId: 'usr_42' }, 'captured params must contain userId');
}
// 4. useParams extracts and merges parameters across nested route layouts
{
let layoutCaptured = null;
let childCaptured = null;
const routes = [
{
path: '/teams/:teamId',
element: React.createElement(LayoutWithProbe, {
onInspect: (p) => {
layoutCaptured = p;
},
}),
children: [
{
path: 'projects/:projectId/tasks/:taskId',
element: React.createElement(ParamsProbe, {
onInspect: (p) => {
childCaptured = p;
},
}),
},
],
},
];
const markup = renderWithMemoryRouter(routes, ['/teams/core-dev/projects/proj-99/tasks/t-1001']);
assert.ok(markup.includes('core-dev'), 'Markup must contain team ID');
assert.ok(markup.includes('t-1001'), 'Markup must contain task ID');
assert.deepStrictEqual(
layoutCaptured,
{ teamId: 'core-dev', projectId: 'proj-99', taskId: 't-1001' },
'Layout probe must receive all matched parameters in active branch'
);
assert.deepStrictEqual(
childCaptured,
{ teamId: 'core-dev', projectId: 'proj-99', taskId: 't-1001' },
'Child probe must receive parent and leaf route parameters'
);
}
// 5. useParams decodes percent-encoded URL values in route parameters
{
let captured = null;
const markup = renderWithMemoryRouter(
[
{
path: '/search/:query',
element: React.createElement(ParamsProbe, {
onInspect: (p) => {
captured = p;
},
}),
},
],
['/search/hello%20world%2Breact']
);
assert.ok(markup.includes('hello world+react'), 'Markup must contain decoded query string');
assert.deepStrictEqual(
captured,
{ query: 'hello world+react' },
'useParams must automatically decode percent-encoded values'
);
}
// 6. useParams handles optional parameter segments when omitted and when supplied
{
let capturedWithout = null;
renderWithMemoryRouter(
[
{
path: '/docs/:version?',
element: React.createElement(ParamsProbe, {
onInspect: (p) => {
capturedWithout = p;
},
}),
},
],
['/docs']
);
assert.deepStrictEqual(
capturedWithout,
{},
'useParams must omit optional parameter or return empty object when omitted'
);
let capturedWith = null;
renderWithMemoryRouter(
[
{
path: '/docs/:version?',
element: React.createElement(ParamsProbe, {
onInspect: (p) => {
capturedWith = p;
},
}),
},
],
['/docs/v6.30']
);
assert.deepStrictEqual(
capturedWith,
{ version: 'v6.30' },
'useParams must capture optional parameter when supplied'
);
}
// 7. useParams captures catch-all wildcard splat parameter via asterisk route
{
let captured = null;
const markup = renderWithMemoryRouter(
[
{
path: '/static/*',
element: React.createElement(ParamsProbe, {
onInspect: (p) => {
captured = p;
},
}),
},
],
['/static/css/themes/dark/main.css']
);
assert.ok(markup.includes('css/themes/dark/main.css'), 'Markup must contain wildcard path');
assert.deepStrictEqual(
captured,
{ '*': 'css/themes/dark/main.css' },
'useParams must capture wildcard rest of path under key "*"'
);
}
// 8. useParams resolves parameters correctly within data routers created via createMemoryRouter and RouterProvider
{
let captured = null;
const routes = [
{
path: '/catalog/:category/items/:itemId',
element: React.createElement(ParamsProbe, {
onInspect: (p) => {
captured = p;
},
}),
},
];
const markup = renderWithDataRouter(routes, {
initialEntries: ['/catalog/electronics/items/sku-4567'],
});
assert.ok(markup.includes('electronics'), 'Data router markup must include category');
assert.ok(markup.includes('sku-4567'), 'Data router markup must include itemId');
assert.deepStrictEqual(
captured,
{ category: 'electronics', itemId: 'sku-4567' },
'useParams must extract all parameters in createMemoryRouter configuration'
);
}
console.log('All react-router-dom.useParams contract tests passed successfully.');
Seeder de origem
anônimo