tastejs/todomvc · error · Error

Cannot determine what kind of selectors this app uses. Add i

Error message

Cannot determine what kind of selectors this app uses. Add it to usesIDSelectors.

What it means

Thrown at cypress/e2e/spec.cy.js:501 during selector-style auto-detection in the setup hook. The spec decides whether to drive the app with ID selectors (`input#new-todo`) or class selectors (`input.new-todo`) by probing the live document (including shadow roots, via findDeep at line 487). Frameworks listed in the `usesIDSelectors` map (line 132, currently only `polymer: false`) bypass detection; for every other framework it inspects the DOM. If BOTH `input#new-todo` AND `input.new-todo` are present the choice is ambiguous, so it throws and asks you to register the framework explicitly rather than guess.

Source

Thrown at cypress/e2e/spec.cy.js:501

      // Walk the document INCLUDING shadow roots — web-component apps
      // (lit, polymer) keep their UI inside a shadow tree, so a plain
      // doc.querySelector misses them. Returns the first element that
      // matches `selector` anywhere in the light or shadow DOM.
      const findDeep = (root, selector) => {
        if (!root) return false
        if (root.querySelector?.(selector)) return true
        const candidates = root.querySelectorAll?.('*') || []
        for (const el of candidates) {
          if (el.shadowRoot && findDeep(el.shadowRoot, selector)) return true
        }
        return false
      }
      cy.document().then(doc => {
        if (framework in usesIDSelectors) {
          setSelectors(usesIDSelectors[framework])
          createTodoCommands(usesIDSelectors[framework])
        } else if (findDeep(doc, 'input#new-todo') && findDeep(doc, 'input.new-todo')) {
          throw new Error(
            'Cannot determine what kind of selectors this app uses. Add it to usesIDSelectors.'
          )
        } else if (findDeep(doc, 'input#new-todo')) {
          cy.log('app uses ID selectors')
          setSelectors(true)
          createTodoCommands(true)
        } else if (findDeep(doc, 'input.new-todo')) {
          cy.log('app uses class selectors')
          setSelectors(false)
          createTodoCommands(false)
        } else {
          throw new Error(
            'Cannot determine what kind of selectors this app uses.'
          )
        }
      })
    })

View on GitHub (pinned to ff43b02e59)

Solutions

  1. Register the framework in the `usesIDSelectors` map at line 132, e.g. `yourframework: true` if the app uses IDs or `yourframework: false` if it uses classes — this short-circuits detection at line 497.
  2. Inspect the rendered DOM (`cy.document().then(d => cy.log(d.querySelector('input#new-todo'), d.querySelector('input.new-todo')))`) to decide which value (true/false) to register.
  3. If the dual-selector is unintentional, fix the app template so it exposes only one of the two conventions.

Example fix

// before (cypress/e2e/spec.cy.js:132)
const usesIDSelectors = {
  polymer: false
}

// after
const usesIDSelectors = {
  polymer: false,
  myframework: true   // app renders <input id="new-todo">
Defensive patterns

Strategy: fallback

Validate before calling

// Before adding a framework to the suite, snapshot which selectors its DOM exposes.
// Run once in `cypress open --env framework=NEWFW` after commenting out the throw, then:
cy.document().then(doc => {
  const hasId = !!doc.querySelector('input#new-todo')
  const hasClass = !!doc.querySelector('input.new-todo')
  cy.log(`id=${hasId} class=${hasClass}`)
  // If both true -> add to usesIDSelectors with the value you intend to drive the app with.
})

Try / catch

// Wrap the detection so an ambiguous framework is reported, not fatal, during onboarding.
cy.document().then(doc => {
  const fw = Cypress.env('framework')
  if (!(fw in usesIDSelectors)) {
    const hasId = findDeep(doc, 'input#new-todo')
    const hasClass = findDeep(doc, 'input.new-todo')
    if (hasId && hasClass) {
      cy.log(`WARNING: ${fw} exposes both selector styles; defaulting to IDs. Add it to usesIDSelectors.`)
      setSelectors(true); createTodoCommands(true); return
    }
  }
  // ... existing branches
})

Prevention

When it happens

Trigger: Running against a framework that is NOT a key in `usesIDSelectors` (anything other than `polymer`) whose rendered DOM contains both an element matching `input#new-todo` and an element matching `input.new-todo`. This commonly happens when a single input carries both id="new-todo" and class="new-todo", or when the app renders two inputs.

Common situations: Adding a new TodoMVC example whose template assigns both the id and the class to the new-todo input; a framework upgrade that changes the markup to include both; a shadow-DOM web-component app (lit/polyderivative) whose shadow tree exposes both selectors. The map at line 132 only whitelists `polymer`, so most real apps fall through to runtime detection.

Related errors


AI-assisted analysis of tastejs/todomvc@ff43b02e59 (2026-08-13). Data as JSON: /api/errors/8e7cb363006ec341. Report an issue: GitHub.