{"record":{"id":"e110c5829319232d","repo":"angular/components","slug":"no-keys-have-been-specified-e110c5","errorCode":null,"errorMessage":"No keys have been specified.","messagePattern":"No keys have been specified\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cdk/testing/testbed/fake-events/type-in-element.ts","lineNumber":138,"sourceCode":"  }\n  const isInput = isTextInput(element);\n  const inputType = element.getAttribute('type') || 'text';\n  const keys: {keyCode?: number; key?: string; code?: string}[] = rest\n    .map(k =>\n      typeof k === 'string'\n        ? k.split('').map(c => ({\n            keyCode: c.toUpperCase().charCodeAt(0),\n            key: c,\n            code: getKeyboardEventCode(c),\n          }))\n        : [k],\n    )\n    .reduce((arr, k) => arr.concat(k), []);\n\n  // Throw an error if no keys have been specified. Calling this function with no\n  // keys should not result in a focus event being dispatched unexpectedly.\n  if (keys.length === 0) {\n    throw getNoKeysSpecifiedError();\n  }\n\n  // We simulate the user typing in a value by incrementally assigning the value below. The problem\n  // is that for some input types, the browser won't allow for an invalid value to be set via the\n  // `value` property which will always be the case when going character-by-character. If we detect\n  // such an input, we have to set the value all at once or listeners to the `input` event (e.g.\n  // the `ReactiveFormsModule` uses such an approach) won't receive the correct value.\n  const enterValueIncrementally =\n    inputType === 'number'\n      ? // The value can be set character by character in number inputs if it doesn't have any decimals.\n        keys.every(key => key.key !== '.' && key.key !== '-' && key.keyCode !== PERIOD)\n      : incrementalInputTypes.has(inputType);\n\n  triggerFocus(element);\n\n  // When we aren't entering the value incrementally, assign it all at once ahead\n  // of time so that any listeners to the key events below will have access to it.\n  if (!enterValueIncrementally) {","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/testing/testbed/fake-events/type-in-element.ts#L120-L156","documentation":"Thrown by the testbed typeInElement utility (used by TestbedHarnessElement's sendKeys and fake event dispatch) when the computed keys array is empty. Typing nothing would still fire a focus event, so getNoKeysSpecifiedError is thrown to avoid the unexpected side effect.","triggerScenarios":"Calling typeInElement(el) with no keys, sendKeys() on a TestBed TestElement with no arguments, or spreading an empty modifiers/key array into it.","commonSituations":"Form-fill test helpers driven by empty data rows; refactored tests where the key literal was removed but the call kept; keyboard-combination helpers passing only modifier names.","solutions":["Pass actual characters/keys: typeInElement('hello', input).","Skip the call when the key list is empty instead of invoking it.","For modifier-only behavior, include a real key in the chord (e.g. `${ctrl}c`)."],"exampleFix":"// before\nawait input.sendKeys(...values.map(String)); // values may be []\n// after\nif (values.length) await input.sendKeys(...values.map(String));","handlingStrategy":"validation","validationCode":"if (!keys || keys.length === 0) return;\ntypeInElement('', input); // never reached with empty key list","typeGuard":"const hasKeys = (k: string[] | undefined): k is [string, ...string[]] => Array.isArray(k) && k.length > 0;","tryCatchPattern":"try { await input.sendKeys(...keys); } catch (e) { if ((e as Error).message.includes('No keys have been specified')) return; throw e; }","preventionTips":["Validate form-fill data before typing (skip empty entries)","Don't call sendKeys/typeInElement solely to focus an element — use focus() instead"],"tags":["angular-cdk","testing","testbed","keyboard-input"],"backgroundTag":"no-keys-specified","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}