angular/components · error

No keys have been specified.

Error message

No keys have been specified.

What it means

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.

Source

Thrown at src/cdk/testing/testbed/fake-events/type-in-element.ts:138

  }
  const isInput = isTextInput(element);
  const inputType = element.getAttribute('type') || 'text';
  const keys: {keyCode?: number; key?: string; code?: string}[] = rest
    .map(k =>
      typeof k === 'string'
        ? k.split('').map(c => ({
            keyCode: c.toUpperCase().charCodeAt(0),
            key: c,
            code: getKeyboardEventCode(c),
          }))
        : [k],
    )
    .reduce((arr, k) => arr.concat(k), []);

  // Throw an error if no keys have been specified. Calling this function with no
  // keys should not result in a focus event being dispatched unexpectedly.
  if (keys.length === 0) {
    throw getNoKeysSpecifiedError();
  }

  // We simulate the user typing in a value by incrementally assigning the value below. The problem
  // is that for some input types, the browser won't allow for an invalid value to be set via the
  // `value` property which will always be the case when going character-by-character. If we detect
  // such an input, we have to set the value all at once or listeners to the `input` event (e.g.
  // the `ReactiveFormsModule` uses such an approach) won't receive the correct value.
  const enterValueIncrementally =
    inputType === 'number'
      ? // The value can be set character by character in number inputs if it doesn't have any decimals.
        keys.every(key => key.key !== '.' && key.key !== '-' && key.keyCode !== PERIOD)
      : incrementalInputTypes.has(inputType);

  triggerFocus(element);

  // When we aren't entering the value incrementally, assign it all at once ahead
  // of time so that any listeners to the key events below will have access to it.
  if (!enterValueIncrementally) {

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Pass actual characters/keys: typeInElement('hello', input).
  2. Skip the call when the key list is empty instead of invoking it.
  3. For modifier-only behavior, include a real key in the chord (e.g. `${ctrl}c`).

Example fix

// before
await input.sendKeys(...values.map(String)); // values may be []
// after
if (values.length) await input.sendKeys(...values.map(String));
Defensive patterns

Strategy: validation

Validate before calling

if (!keys || keys.length === 0) return;
typeInElement('', input); // never reached with empty key list

Type guard

const hasKeys = (k: string[] | undefined): k is [string, ...string[]] => Array.isArray(k) && k.length > 0;

Try / catch

try { await input.sendKeys(...keys); } catch (e) { if ((e as Error).message.includes('No keys have been specified')) return; throw e; }

Prevention

When it happens

Trigger: Calling typeInElement(el) with no keys, sendKeys() on a TestBed TestElement with no arguments, or spreading an empty modifiers/key array into it.

Common situations: 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.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/e110c5829319232d. Report an issue: GitHub.