{
  "doc": {
    "id": "app/extend/custom-frameworks",
    "title": "Custom frameworks",
    "description": "Learn how to create a custom Framework Definition and Mount Adapter for your favorite library or framework.",
    "section": "app",
    "source_path": "/llm/markdown/app/extend/custom-frameworks.md",
    "version": "066c46e056f0f322a0670d2d3aa4e6adaebfe717",
    "updated_at": "2026-09-10T13:30:12.426Z",
    "headings": [
      {
        "id": "app/extend/custom-frameworks#custom-component-testing-frameworks",
        "text": "Custom component testing frameworks",
        "level": 1
      },
      {
        "id": "app/extend/custom-frameworks#concepts",
        "text": "Concepts",
        "level": 2
      },
      {
        "id": "app/extend/custom-frameworks#framework-definition",
        "text": "Framework Definition",
        "level": 2
      },
      {
        "id": "app/extend/custom-frameworks#mount-adapter",
        "text": "Mount Adapter",
        "level": 2
      },
      {
        "id": "app/extend/custom-frameworks#package-json",
        "text": "package.json",
        "level": 2
      },
      {
        "id": "app/extend/custom-frameworks#testing",
        "text": "Testing",
        "level": 2
      },
      {
        "id": "app/extend/custom-frameworks#publishing-on-npm",
        "text": "Publishing on npm",
        "level": 2
      },
      {
        "id": "app/extend/custom-frameworks#available-framework-definitions",
        "text": "Available Framework Definitions",
        "level": 2
      }
    ]
  },
  "content": {
    "type": "root",
    "children": [
      {
        "type": "heading",
        "depth": 1,
        "children": [
          {
            "type": "text",
            "value": "Custom component testing frameworks"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress Component Testing includes "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/component-testing/get-started.md#Supported-Frameworks",
            "children": [
              {
                "type": "text",
                "value": "official support"
              }
            ]
          },
          {
            "type": "text",
            "value": " for many popular libraries and frameworks such as "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/component-testing/react/overview.md",
            "children": [
              {
                "type": "text",
                "value": "React"
              }
            ]
          },
          {
            "type": "text",
            "value": ", "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/component-testing/angular/overview.md",
            "children": [
              {
                "type": "text",
                "value": "Angular"
              }
            ]
          },
          {
            "type": "text",
            "value": ", and "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/component-testing/vue/overview.md",
            "children": [
              {
                "type": "text",
                "value": "Vue"
              }
            ]
          },
          {
            "type": "text",
            "value": ". All officially supported libraries feature a first class onboarding experience, where we detect and scaffold the correct files, and a framework-specific `mount` adapter to render your components. We call this collection of features a Framework Definition since it defines the requirements for a library or framework to work in Cypress."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If your favorite library isn't featured, don't worry - we expose the same API we use internally for the Cypress community to define their own Framework Definitions."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In this guide, you'll learn how to author a Framework Definition, which will enjoy the same polished onboarding experience as our officially supported frameworks."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Concepts"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "There are a few requirements for authoring a Framework Definition."
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Framework-Definition",
                    "children": [
                      {
                        "type": "text",
                        "value": "Definition File"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " (we recommending naming this `definition.cjs`)"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Mount-Adapter",
                    "children": [
                      {
                        "type": "text",
                        "value": "Mount Adapter"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " (we recommending naming this `index.mjs`)"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "A "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "#packagejson",
                    "children": [
                      {
                        "type": "text",
                        "value": "`package.json`"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " with the correct conventions"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The Definition is required when users configure Component Testing for the first time. The Mount adapter is used to render components when writing tests."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To simplify this process, we recommend starting development using "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-ct-definition-template",
            "children": [
              {
                "type": "text",
                "value": "our official template"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Framework Definition"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Below is a minimal Framework Definition. Note that `defineFrameworkDefinition` is purely for type safety, similar to `defineConfig` in `cypress.config`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "There is one important convention; the `type` key in `defineFrameworkDefinition` should match the name of your package on npm, and should be named using one of the following conventions:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`cypress-ct-*`"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`@organization/cypress-ct-*`"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Some examples of valid names include:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`cypress-ct-react-js`"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`cypress-ct-svelte-testing`"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`@cypress/cypress-ct-react`"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`@angular/cypress-ct-angular`"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When configuring a project to use Component Testing, Cypress will load any dependencies following this naming convention from the project's `node_modules` and present them as framework options."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A simple example of a Framework Definition for the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.solidjs.com/",
            "children": [
              {
                "type": "text",
                "value": "Solid.js"
              }
            ]
          },
          {
            "type": "text",
            "value": " library is shown below. We generally recommend naming this `definition.cjs`. In our "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-ct-definition-template",
            "children": [
              {
                "type": "text",
                "value": "official template"
              }
            ]
          },
          {
            "type": "text",
            "value": ", this file is at the root level of the package."
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "const { defineFrameworkDefinition } = require('cypress')\n\nconst solidDep = {\n  // Unique, semantic identifier.\n  type: 'solid-js',\n\n  // Human readable name.\n  name: 'Solid',\n\n  // Package name install from `npm`.\n  package: 'solid-js',\n\n  /**\n   * Similar to package, but can include a version or tag.\n   * Used during setup to generate an install command for users.\n   * Eg: `solid-js@next`\n   */\n  installer: 'solid-js',\n\n  // Human readable description.\n  description:\n    'A declarative, efficient, and flexible JavaScript library for building user interfaces.',\n\n  // Minimum supported version.\n  minVersion: '^1.6.0',\n}\n\n/**\n * Similar to above. Create an smooth, seamless setup experience\n * by ensuring the user has all the necessary dependencies.\n * @type {Cypress.CypressComponentDependency}\n */\nconst solidVitePlugin = {\n  type: 'solid-js-vite-plugin',\n  name: 'Vite Plugin Solid',\n  package: 'vite-plugin-solid',\n  installer: 'vite-plugin-solid',\n  description: 'A simple integration to run solid-js with vite',\n  minVersion: '^1.6.0 || ^2.0.0',\n}\n\n/**\n * The actual definition.\n */\nmodule.exports = defineFrameworkDefinition({\n  /**\n   * This should match the `npm` package name.\n   * The convention required to ensure your Definition is processed\n   * by Cypress is `cypress-ct-*` for global packages, or\n   * `@org/cypress-ct-*` for organization level packages.\n   */\n  type: '@lmiller1990/cypress-ct-solid-js',\n\n  /**\n   * The label that shows up when configuring Component Testing\n   * for the first time.\n   */\n  name: 'Solid.js',\n\n  /**\n   * Supported bundlers. Can be \"webpack\" and/or \"vite\".\n   * In this example we only support Solid.js with Vite.\n   */\n  supportedBundlers: ['vite'],\n\n  /**\n   * Used by Cypress to automatically detect the correct Framework Definition\n   * based on the user's project.\n   * In this example, if a module matching `solidDep`\n   * is found in the user's project,\n   * Solid.js will automatically be selected when configuring Component Testing.\n   */\n  detectors: [solidDep],\n\n  /**\n   * Supply a set of dependencies a project should have to use this Framework Definition. The user will be prompted to install them if they are not found.\n   * Optionally, supply different dependencies based on the chosen bundler.\n   */\n  dependencies: (bundler) => {\n    return [solidDep, solidVitePlugin]\n  },\n\n  /**\n   * An SVG icon. Shown when configuring Component Testing for the first time.\n   * Optional, but good for branding your Framework Definition.\n   */\n  icon: `\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 166 155.3\"><path d=\"M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z\" fill=\"#76b3e1\"/><linearGradient id=\"a\" gradientUnits=\"userSpaceOnUse\" x1=\"27.5\" y1=\"3\" x2=\"152\" y2=\"63.5\"><stop offset=\".1\" stop-color=\"#76b3e1\"/><stop offset=\".3\" stop-color=\"#dcf2fd\"/><stop offset=\"1\" stop-color=\"#76b3e1\"/></linearGradient><path d=\"M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z\" opacity=\".3\" fill=\"url(#a)\"/><path d=\"M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z\" fill=\"#518ac8\"/><linearGradient id=\"b\" gradientUnits=\"userSpaceOnUse\" x1=\"95.8\" y1=\"32.6\" x2=\"74\" y2=\"105.2\"><stop offset=\"0\" stop-color=\"#76b3e1\"/><stop offset=\".5\" stop-color=\"#4377bb\"/><stop offset=\"1\" stop-color=\"#1f3b77\"/></linearGradient><path d=\"M52 35l-4 1c-17 5-22 21npm install https://cdn.cypress.io/beta/npm/12.6.0/darwin-arm64/feature/ct-public-api-ab820f062d313fbef51665bdd1d883c69d89b3be/cypress.tgz-13 35 10 13 31 20 48 15l62-21S92 26 52 35z\" opacity=\".3\" fill=\"url(#b)\"/><linearGradient id=\"c\" gradientUnits=\"userSpaceOnUse\" x1=\"18.4\" y1=\"64.2\" x2=\"144.3\" y2=\"149.8\"><stop offset=\"0\" stop-color=\"#315aa9\"/><stop offset=\".5\" stop-color=\"#518ac8\"/><stop offset=\"1\" stop-color=\"#315aa9\"/></linearGradient><path d=\"M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z\" fill=\"url(#c)\"/><linearGradient id=\"d\" gradientUnits=\"userSpaceOnUse\" x1=\"75.2\" y1=\"74.5\" x2=\"24.4\" y2=\"260.8\"><stop offset=\"0\" stop-color=\"#4377bb\"/><stop offset=\".5\" stop-color=\"#1a336b\"/><stop offset=\"1\" stop-color=\"#1a336b\"/></linearGradient><path d=\"M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z\" fill=\"url(#d)\"/></svg>\n  `,\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Our Framework Definition shows up in Cypress! It has the \"community\" label, indicating it's a third party definition."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We defined the `dependencies`, which are also correctly handled - we haven't installed them all, so Cypress is prompting us to do so:"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Mount Adapter"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The second part of defining a Framework Definition is the Mount Adapter. This is the function that renders the component in your tests using `cy.mount()`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "By default, Cypress will look for this as a `mount` function that is a named export from the package. This should be written in a `index.mjs` file. This example is for a "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.solidjs.com/",
            "children": [
              {
                "type": "text",
                "value": "Solid.js"
              }
            ]
          },
          {
            "type": "text",
            "value": " mount adapter:"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import { getContainerEl, setupHooks } from '@cypress/mount-utils'\nimport { render } from 'solid-js/web'\n\nlet dispose\n\nfunction cleanup() {\n  dispose?.()\n}\n\n/**\n * @param {() => JSX.Element} - component to render\n */\nexport function mount(component, options = {}) {\n  // Retrieve root DOM element that Cypress has prepared for this test\n  const root = getContainerEl()\n\n  dispose = render(() => component, root)\n\n  // Wait until next microtick to ensure any async render logic has executed\n  return cy.wait(0, { log: false }).then(() => {\n    if (options.log !== false) {\n      Cypress.log({\n        name: 'mount',\n        message: 'Mounted component',\n      })\n    }\n  })\n}\n\n// Cleanup between each test\nsetupHooks(cleanup)"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "This is different for each library, but the concept is the same - identify how to mount or render a component in your library, and implement it in a function named `mount` in `index.mjs`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When a user configures Component Testing with your Framework Definition we automatically configure a `cy.mount` command using your `mount` function in the Component Testing `supportFile`:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress/support/component.js"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress/support/component.ts"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import { mount } from '@lmiller1990/cypress-ct-solid-js'\n\nCypress.Commands.add('mount', mount)"
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import { mount } from '@lmiller1990/cypress-ct-solid-js'\n\ndeclare global {\n  namespace Cypress {\n    interface Chainable {\n      mount: typeof mount\n    }\n  }\n}\n\nCypress.Commands.add('mount', mount)"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "package.json"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The final thing you need is a correctly configured `package.json`. This example was created using "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-ct-definition-template",
            "children": [
              {
                "type": "text",
                "value": "our official template"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "There are two fields of note:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`name`: Your package name which must follow the `cypress-ct-*`/`@org/cypress-ct-*` convention"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "`exports`: Object referencing the two files we created to comprise the Framework Definition. The `node` entry points to the Definition file, and the `default` entry points to the Mount Adapter:"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "{\n  \"name\": \"@lmiller1990/cypress-ct-solid-js\",\n  \"version\": \"0.0.4\",\n  \"description\": \"Example Framework Definition for Cypress and Solid.js\",\n  \"exports\": {\n    \"node\": \"./definition.cjs\",\n    \"default\": \"./index.mjs\"\n  },\n  \"files\": [\n    \"package.json\",\n    \"definition.cjs\",\n    \"index.mjs\"\n  ],\n  \"dependencies\": {\n    \"@cypress/mount-utils\": \"^4.0.0\"\n  },\n  \"devDependencies\": {\n    \"solid-js\": \"^1.6.0\"\n  },\n  \"peerDependencies\": {\n    \"solid-js\": \"^1.6.0\"\n    \"cypress\": \"^12.7.0\"\n  }\n}"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Testing"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If you develop the Framework Definition file using TypeScript, for example by using "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-ct-definition-template",
            "children": [
              {
                "type": "text",
                "value": "our official template"
              }
            ]
          },
          {
            "type": "text",
            "value": ", as long as you don't have any compile time errors, everything should work as expected. If you do run into unexpected behavior, please "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress/issues",
            "children": [
              {
                "type": "text",
                "value": "file an issue"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Mount Adapters can be more complex to test. In general, we recommend testing them in the same way users consume them - using Cypress Component Testing. A minimal test suite for a simple Solid.js Mount Adapter can be found "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/lmiller1990/cypress-ct-solid-js/tree/main/example-project",
            "children": [
              {
                "type": "text",
                "value": "here"
              }
            ]
          },
          {
            "type": "text",
            "value": ". Alternatively, take a look at our official "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress/tree/develop/npm/react",
            "children": [
              {
                "type": "text",
                "value": "React"
              }
            ]
          },
          {
            "type": "text",
            "value": " and "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress/tree/develop/npm/angular",
            "children": [
              {
                "type": "text",
                "value": "Angular"
              }
            ]
          },
          {
            "type": "text",
            "value": " Mount Adapters, both of which have extensive test suites."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Publishing on npm"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "That's it! Publish your Framework Definition on npm and start using it."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Available Framework Definitions"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can find a list of available Framework Definitions "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/component-testing/get-started.md#Supported-Frameworks",
            "children": [
              {
                "type": "text",
                "value": "here"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If you have created a Framework Definition we would be delighted to mention it in our documentation so other Cypress users on the same framework can find it. "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-documentation/blob/main/CONTRIBUTING.md",
            "children": [
              {
                "type": "text",
                "value": "Please submit a Pull Request"
              }
            ]
          },
          {
            "type": "text",
            "value": "!"
          }
        ]
      }
    ]
  },
  "token_estimate": 1883
}