Connecting Spur to GitHub Actions runs your configured Test Plans when the workflow triggers and reports commit status checks. To block merging on failed tests, configure the required checks in your branch protection rules.
For @spur comment requests, generated tests, or testing instructions, see the PR Agent. It uses the Spur GitHub App and does not need the workflow files on this page.
Open the Integrations page in your Spur dashboard and connect GitHub.
Open Spur Integrations
Connect Spur with GitHub to get started
2
Open GitHub settings
Once connected, find GitHub on the Integrations page and click Settings.
Click Settings on the GitHub integration card
3
Configure your integration
If GitHub settings show tabs, select CI/CD. Review these sections before proceeding.
API key
Your unique Spur API key authenticates your GitHub repository with Spur. Copy it if you need to reference it manually.
Directory path
The path where your GitHub Actions workflow files will be stored. The default is .github/workflows. Leave this as is unless your repository uses a custom structure.
Enabled Test Plans
Select which Test Plans should run as part of your CI/CD pipeline. Click + Add Test Plan to include additional ones.
YAML files
Spur generates two workflow files for you here. You will download and add these to your repository in the next step.
Other integrations: You can also allow other integrations to be enabled for GitHub jobs.
Enable other integrations for GitHub jobs
The GitHub Integration Settings page
4
Add the YAML files to your repository
Download both YAML files from the settings page and add them to your repository under .github/workflows/.The Test Plan Trigger file contains your API key in its spur-github-key header. Before you commit it, store the key as a repository secret named SPUR_API_KEY and change the header to -H "spur-github-key: ${{ secrets.SPUR_API_KEY }}".
These two files are what make the integration work. Without them in your repository, Spur doesn’t trigger on pull requests and no quality gate is in place. Do not skip this step.
Report Generation — generates and publishes test reports after each run
Test Plan Trigger — tells GitHub when to trigger a Spur Test Plan run
Add both YAML files to your repository's .github/workflows/ directory
5
Save changes
Click Save Changes to finalize your integration. From this point, Spur runs your selected Test Plans automatically on every pull request.
This workflow runs when a pull request is opened or updated. It calls the Spur webhook with your API key, the commit SHA, and the repository name, which triggers your enabled Test Plans. Each Test Plan posts an individual commit status back to the PR as tests execute.The generated file runs only on pull requests that target ext/spur/github. Change the branch under branches: to the branch your pull requests target, such as main.To run tests against a deploy preview, see Testing deploy previews. To run only some of your enabled Test Plans, see Running specific test plans.
You can use the CICD - All tests status as a required status check in GitHub branch protection rules. This blocks merging until every Test Plan in the pipeline has passed.To set this up:
Go to your repository’s Settings > Branches > Branch protection rules
Enable Require status checks to pass before merging
Need to test against a Vercel preview deploy or feature branch URL? Use Override URLs to redirect tests at runtime without changing your environment settings.
{"docsConfig":{"theme":"maple","$schema":"https://mintlify.com/docs.json","name":"Spur Documentation","description":"Spur is an AI-powered QA engineer. Create, run, and analyze automated end-to-end tests for web and mobile apps using natural language.","colors":{"primary":"#0535dd","light":"#7293fc","dark":"#0432c8"},"logo":{"light":"https://mintcdn.com/spur/cytvGy0qHI_KqMmI/logo/logo.png?fit=max\u0026auto=format\u0026n=cytvGy0qHI_KqMmI\u0026q=85\u0026s=f931455ec7ab89b4f23bea661c49b9a0","dark":"https://mintcdn.com/spur/cytvGy0qHI_KqMmI/logo/logo.png?fit=max\u0026auto=format\u0026n=cytvGy0qHI_KqMmI\u0026q=85\u0026s=f931455ec7ab89b4f23bea661c49b9a0"},"favicon":"https://mintcdn.com/spur/PGSKxMZrMj-HShvG/favicon.png?fit=max\u0026auto=format\u0026n=PGSKxMZrMj-HShvG\u0026q=85\u0026s=15b039b8d8cc786e659efff9c0636668","appearance":{"default":"light","strict":true},"background":{"color":{"light":"#fcfcfc","dark":"#111111"}},"navbar":{"links":[{"href":"https://app.spurtest.com/signin","label":"Sign In"}],"primary":{"type":"button","label":"Book a Demo","href":"https://www.spurtest.com/book-a-demo"}},"footer":{"socials":{"x":"https://x.com/spur_dev","linkedin":"https://www.linkedin.com/company/spur-test"}},"search":{"prompt":"Search docs..."},"seo":{"metatags":{"canonical":"https://docs.spurtest.com"}},"fonts":{"family":"Inter"},"errors":{"404":{"redirect":true}},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","cursor","vscode"],"display":"header"},"markdown":{"instructions":["Spur is an AI-powered QA engineer that lets teams create and run automated end-to-end tests for web and mobile apps using natural language.","When answering questions about Spur, cite the relevant page from docs.spurtest.com."]},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"spur","hasAudioNarration":false,"actualSubdomain":"spur","customDomains":["docs.spurtest.com"],"gitSource":{"type":"github","owner":"tryspur-dev","repo":"spur_docs","deployBranch":"staging","contentDirectory":"","isPrivate":true,"mountPath":"","label":"","_id":"6aea37bd5a179a60130b2166"},"feedback":{"thumbs":true,"edits":true,"agentFeedback":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6af11d673de17d5f9fbb8664","clientVersion":"0.0.4088","searchFilterCounts":[{"language":"default","tag":"Documentation","count":109},{"language":"default","tag":"Authoring Tests","count":42},{"language":"default","tag":"Test Side Peek","count":33},{"language":"default","tag":"Step Types","count":26},{"language":"default","tag":"Analyzing Tests","count":23},{"language":"default","tag":"Additional Resources","count":11},{"language":"default","tag":"Getting Started","count":11},{"language":"default","tag":"Integrations","count":10},{"language":"default","tag":"Running Tests","count":10},{"language":"default","tag":"Managing Tests","count":8}]},"assistantConfig":{},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"styles.css","content":"@font-face{font-family:\"Geist Mono\";font-style:normal;font-weight:100 900;font-display:swap;src:url(\"https://fonts.gstatic.com/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrcdmhHkjko.woff2\") format(\"woff2\")}html:root{--gray-50: 250 250 250;--gray-100: 245 245 245;--gray-200: 235 234 234;--gray-300: 215 213 213;--gray-400: 145 141 141;--gray-500: 114 110 110;--gray-600: 82 80 80;--gray-700: 62 60 60;--gray-800: 42 40 40;--gray-900: 26 25 25;--gray-950: 10 10 10;--default-border-color: 235 234 234}#content{color:rgb(var(--gray-900));font-size:1rem;line-height:1.5rem;letter-spacing:-0.01em}#header .prose{color:rgb(var(--gray-500));font-size:1.125rem;line-height:1.75rem;letter-spacing:-0.0175em}#page-title,#content h1:not(.not-prose){color:rgb(var(--gray-900));font-size:1.875rem;font-weight:600;line-height:2.25rem;letter-spacing:-0.025em}#content h2:not(.not-prose){color:rgb(var(--gray-900));font-size:1.5rem;font-weight:600;line-height:2rem;letter-spacing:-0.02em}#content h3:not(.not-prose){font-size:1.25rem;font-weight:600;line-height:1.75rem;letter-spacing:-0.0175em}#content h4:not(.not-prose){font-size:1.125rem;font-weight:600;line-height:1.75rem;letter-spacing:-0.0175em}#sidebar,#sidebar-content,#header .eyebrow,#page-context-menu,.nav-tabs,#search-bar-entry,#table-of-contents,#pagination{font-size:0.875rem;line-height:1.25rem;letter-spacing:-0.005em}#content code,#content pre,kbd{font-family:\"Geist Mono\", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;letter-spacing:normal}#pagination{gap:1.5rem;padding:0;background:transparent}#pagination a{padding:0.5rem 0;border-radius:0.375rem}#pagination a:focus-visible,#search-bar-entry:focus-visible{outline:2px solid rgb(var(--primary-light));outline-offset:2px}#pagination a>div{gap:0.75rem;height:auto;min-height:2.5rem;background:transparent;box-shadow:none}#pagination a>div>div{padding:0}#pagination a>div>div:empty,#pagination [data-component-part=\"pagination-description\"]{display:none}#pagination [data-component-part=\"pagination-title\"]{overflow:visible;white-space:normal;text-overflow:clip}"}],"page":{"pagePath":"running-tests/cicd/github","slug":"/running-tests/cicd/github","pageMetadata":{"title":"GitHub","icon":"github","iconType":"brands","description":"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.","href":"/running-tests/cicd/github"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{Card,CodeBlock,Columns,Frame,Heading,Note,OptimizedImage,Step,Steps,Warning}=_components;if(!Card)_missingMdxReference(`Card`,true);if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Columns)_missingMdxReference(`Columns`,true);if(!Frame)_missingMdxReference(`Frame`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Note)_missingMdxReference(`Note`,true);if(!OptimizedImage)_missingMdxReference(`OptimizedImage`,true);if(!Step)_missingMdxReference(`Step`,true);if(!Steps)_missingMdxReference(`Steps`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(Heading,{level:`2`,id:`overview`,children:`Overview`}),`\n`,_jsx(_components.p,{children:`Connecting Spur to GitHub Actions runs your configured Test Plans when the workflow triggers and reports commit status checks. To block merging on failed tests, configure the required checks in your branch protection rules.`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[`For `,_jsx(_components.code,{children:`@spur`}),` comment requests, generated tests, or testing instructions, see the `,_jsx(_components.a,{href:`/running-tests/cicd/pr-agent`,children:`PR Agent`}),`. It uses the Spur GitHub App and does not need the workflow files on this page.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`what-you-get`,children:`What you get`}),`\n`,_jsxs(Columns,{cols:2,children:[_jsx(Card,{icon:`play`,title:`Automated test execution`,children:_jsx(_components.p,{children:`Test Plans run automatically on every pull request without manual intervention.`})}),_jsx(Card,{icon:`circle-check`,title:`PR status checks`,children:_jsx(_components.p,{children:`Pass/fail results appear directly on your pull requests.`})}),_jsx(Card,{icon:`shield-check`,title:`Deployment quality gate`,children:_jsx(_components.p,{children:`Tests run right before deployment, catching issues before they reach production.`})}),_jsx(Card,{icon:`lock`,title:`Branch protection`,children:_jsx(_components.p,{children:`Prevent merging pull requests with failing tests using GitHub branch protection rules.`})})]}),`\n`,_jsx(Heading,{level:`2`,id:`setup`,children:`Setup`}),`\n`,_jsxs(Steps,{children:[_jsxs(Step,{title:`Go to integrations`,children:[_jsx(_components.p,{children:`Open the Integrations page in your Spur dashboard and connect GitHub.`}),_jsx(Card,{icon:`github`,horizontal:true,href:`https://app.spurtest.com/integrations`,title:`Open Spur Integrations`,children:_jsx(_components.p,{children:`Connect Spur with GitHub to get started`})})]}),_jsxs(Step,{title:`Open GitHub settings`,children:[_jsxs(_components.p,{children:[`Once connected, find GitHub on the Integrations page and click `,_jsx(_components.strong,{children:`Settings`}),`.`]}),_jsx(Frame,{caption:`Click Settings on the GitHub integration card`,children:_jsx(OptimizedImage,{src:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-settings.png?fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=624e109dc9abfab4de1f7d393ee7aaac`,alt:`GitHub integration settings`,\"data-og-width\":`1070`,width:`1070`,\"data-og-height\":`150`,height:`150`,\"data-path\":`images/running-tests/cicd/github/github-integration-settings.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-settings.png?w=280\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=669b32b41d172e116c3e4faae8a1e452 280w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-settings.png?w=560\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=187a077df9b317bf62a0207ffb6a3ef3 560w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-settings.png?w=840\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=562ef948df0c3ac81ba9fc2f536d89fb 840w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-settings.png?w=1100\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=9407d109b4d4002f7f3164e281574b93 1100w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-settings.png?w=1650\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=b5592eca0f0efc0d51ba6f7f1417b32e 1650w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-settings.png?w=2500\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=f9d70c79c9cfe1133b082d67b8f7b8bd 2500w`})})]}),_jsxs(Step,{title:`Configure your integration`,children:[_jsxs(_components.p,{children:[`If GitHub settings show tabs, select `,_jsx(_components.strong,{children:`CI/CD`}),`. Review these sections before proceeding.`]}),_jsxs(Columns,{cols:2,children:[_jsx(Card,{icon:`key`,title:`API key`,children:_jsx(_components.p,{children:`Your unique Spur API key authenticates your GitHub repository with Spur. Copy it if you need to reference it manually.`})}),_jsx(Card,{icon:`folder`,title:`Directory path`,children:_jsxs(_components.p,{children:[`The path where your GitHub Actions workflow files will be stored. The default is `,_jsx(_components.code,{children:`.github/workflows`}),`. Leave this as is unless your repository uses a custom structure.`]})}),_jsx(Card,{icon:`list-check`,title:`Enabled Test Plans`,children:_jsxs(_components.p,{children:[`Select which Test Plans should run as part of your CI/CD pipeline. Click `,_jsx(_components.strong,{children:`+ Add Test Plan`}),` to include additional ones.`]})}),_jsx(Card,{icon:`file-code`,title:`YAML files`,children:_jsx(_components.p,{children:`Spur generates two workflow files for you here. You will download and add these to your repository in the next step.`})})]}),_jsxs(Note,{children:[_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Other integrations:`}),` You can also allow other integrations to be enabled for GitHub jobs.`]}),_jsx(Frame,{caption:`Enable other integrations for GitHub jobs`,children:_jsx(OptimizedImage,{src:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/enable-other-integrations-github-jobs.png?fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=8a136703ecd4c6b0996c11995c18052b`,alt:`Enable other integrations for GitHub jobs`,\"data-og-width\":`1164`,width:`1164`,\"data-og-height\":`178`,height:`178`,\"data-path\":`images/running-tests/cicd/github/enable-other-integrations-github-jobs.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/enable-other-integrations-github-jobs.png?w=280\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=57b53ec810e9f10d0178c2cdccb632df 280w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/enable-other-integrations-github-jobs.png?w=560\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=0dd3879fa5ff5d2e1435023bab7ccfea 560w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/enable-other-integrations-github-jobs.png?w=840\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=9682587cab2c8c6b95d63fb3623bfc6d 840w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/enable-other-integrations-github-jobs.png?w=1100\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=f29a4a31ef8f9ad5b033cd9c33d73e29 1100w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/enable-other-integrations-github-jobs.png?w=1650\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=cc22b1c087b80dd15a70439187d32174 1650w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/enable-other-integrations-github-jobs.png?w=2500\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=34866a3898aac2b5d06bddeb8699ac09 2500w`})})]}),_jsx(Frame,{caption:`The GitHub Integration Settings page`,children:_jsx(OptimizedImage,{src:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-configuration.png?fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=68b72b75ab96a8e12b617d194125f122`,alt:`GitHub integration configuration`,\"data-og-width\":`1102`,width:`1102`,\"data-og-height\":`1100`,height:`1100`,\"data-path\":`images/running-tests/cicd/github/github-integration-configuration.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-configuration.png?w=280\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=fdcc2ec053cf3b64781bcdb1dc90fb17 280w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-configuration.png?w=560\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=a471be99ff2e468cfed9f4cb2c1f5940 560w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-configuration.png?w=840\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=0efc73d2ca1881d110bfbeb1030fb558 840w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-configuration.png?w=1100\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=59d3ea16813458bb35b1317eb7e902ac 1100w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-configuration.png?w=1650\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=e446926fa1ee9d5c2821ba6901d9ec76 1650w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/github-integration-configuration.png?w=2500\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=b395e6309d884d5c5e65c1dfcc4bd715 2500w`})})]}),_jsxs(Step,{title:`Add the YAML files to your repository`,children:[_jsxs(_components.p,{children:[`Download both YAML files from the settings page and add them to your repository under `,_jsx(_components.code,{children:`.github/workflows/`}),`.`]}),_jsxs(_components.p,{children:[`The `,_jsx(_components.strong,{children:`Test Plan Trigger`}),` file contains your API key in its `,_jsx(_components.code,{children:`spur-github-key`}),` header. Before you commit it, store the key as a repository secret named `,_jsx(_components.code,{children:`SPUR_API_KEY`}),` and change the header to `,_jsx(_components.code,{children:'-H \"spur-github-key: ${{ secrets.SPUR_API_KEY }}\"'}),`.`]}),_jsxs(Warning,{children:[_jsx(_components.p,{children:`These two files are what make the integration work. Without them in your repository, Spur doesn’t trigger on pull requests and no quality gate is in place. Do not skip this step.`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Report Generation`}),` — generates and publishes test reports after each run`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Test Plan Trigger`}),` — tells GitHub when to trigger a Spur Test Plan run`]}),`\n`]})]}),_jsx(Frame,{caption:`Add both YAML files to your repository's .github/workflows/ directory`,children:_jsx(OptimizedImage,{src:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png?fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=9c4145b0503fc799ea82cb40f160939e`,alt:`Adding YAML files to GitHub repository`,\"data-og-width\":`1016`,width:`1016`,\"data-og-height\":`234`,height:`234`,\"data-path\":`images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png?w=280\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=eae685bef762e1ed661db348b1ef1fda 280w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png?w=560\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=6171448a3c8e86a64dc9550b699db74a 560w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png?w=840\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=027bf7f33806a95d878531bbb1281ba0 840w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png?w=1100\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=8eff732959faed2837cc1238a1b5ebbb 1100w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png?w=1650\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=1a4b130da87ee9e2747b1cc9372728da 1650w, https://mintcdn.com/spur/8SIYEB8X4PSFcROt/images/running-tests/cicd/github/adding-yaml-files-to-github-repository.png?w=2500\u0026fit=max\u0026auto=format\u0026n=8SIYEB8X4PSFcROt\u0026q=85\u0026s=bef6b842c66ea9f40001901a89a0d487 2500w`})})]}),_jsx(Step,{title:`Save changes`,children:_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Save Changes`}),` to finalize your integration. From this point, Spur runs your selected Test Plans automatically on every pull request.`]})})]}),`\n`,_jsx(Heading,{level:`2`,id:`how-the-workflow-files-work`,children:`How the workflow files work`}),`\n`,_jsx(_components.p,{children:`The two YAML files you download from the settings page serve different purposes:`}),`\n`,_jsx(Heading,{level:`3`,id:`test-plan-trigger`,children:`Test Plan trigger`}),`\n`,_jsx(_components.p,{children:`This workflow runs when a pull request is opened or updated. It calls the Spur webhook with your API key, the commit SHA, and the repository name, which triggers your enabled Test Plans. Each Test Plan posts an individual commit status back to the PR as tests execute.`}),`\n`,_jsxs(_components.p,{children:[`The generated file runs only on pull requests that target `,_jsx(_components.code,{children:`ext/spur/github`}),`. Change the branch under `,_jsx(_components.code,{children:`branches:`}),` to the branch your pull requests target, such as `,_jsx(_components.code,{children:`main`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`To run tests against a deploy preview, see `,_jsx(_components.a,{href:`#testing-deploy-previews`,children:`Testing deploy previews`}),`. To run only some of your enabled Test Plans, see `,_jsx(_components.a,{href:`/running-tests/cicd/overview#running-specific-test-plans`,children:`Running specific test plans`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`report-generation`,children:`Report generation`}),`\n`,_jsx(_components.p,{children:`This workflow listens for status events on your repository. After each Spur Test Plan finishes and posts its commit status, the report workflow:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsx(_components.li,{children:`Collects all Spur-related commit statuses for the PR`}),`\n`,_jsx(_components.li,{children:`Generates a markdown report table with pass, fail, pending, and error counts for each Test Plan`}),`\n`,_jsxs(_components.li,{children:[`Creates or updates a single PR comment (identified by a `,_jsx(_components.code,{children:`## Spur CI/CD Report`}),` header) so your PR stays clean`]}),`\n`,_jsxs(_components.li,{children:[`Sets a summary commit status called `,_jsx(_components.strong,{children:`CICD - All tests`}),` that reflects the overall result`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`The summary status auto-updates as individual Test Plans complete, so you always see the latest state.`}),`\n`,_jsx(Heading,{level:`3`,id:`using-the-summary-status-for-branch-protection`,children:`Using the summary status for branch protection`}),`\n`,_jsxs(_components.p,{children:[`You can use the `,_jsx(_components.strong,{children:`CICD - All tests`}),` status as a required status check in GitHub branch protection rules. This blocks merging until every Test Plan in the pipeline has passed.`]}),`\n`,_jsx(_components.p,{children:`To set this up:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Go to your repository’s `,_jsx(_components.strong,{children:`Settings > Branches > Branch protection rules`})]}),`\n`,_jsxs(_components.li,{children:[`Enable `,_jsx(_components.strong,{children:`Require status checks to pass before merging`})]}),`\n`,_jsxs(_components.li,{children:[`Search for and select `,_jsx(_components.strong,{children:`CICD - All tests`})]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`testing-deploy-previews`,children:`Testing deploy previews`}),`\n`,_jsxs(_components.p,{children:[`Need to test against a Vercel preview deploy or feature branch URL? Use `,_jsx(_components.a,{href:`/running-tests/cicd/override-urls`,children:`Override URLs`}),` to redirect tests at runtime without changing your environment settings.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Run Spur Tests`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`|`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` curl -X POST \\\\`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` -H \"Content-Type: application/json\" \\\\`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:' -H \"spur-github-key: ${{ secrets.SPUR_API_KEY }}\" \\\\'})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:' -H \"sha: ${{ github.sha }}\" \\\\'})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:' -H \"repo: ${{ github.repository }}\" \\\\'})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:' -d \"{\\\\\"override_urls\\\\\": {\\\\\"default\\\\\": \\\\\"${{ steps.deploy.outputs.preview_url }}\\\\\"}}\" \\\\'})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"https://app.spurtest.com/api/webhook/github\"`})}),`\n`]})})})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"GitHub","icon":"github","iconType":"brands","description":"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.","href":"/running-tests/cicd/github"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Overview","slug":"overview","depth":2,"children":[]},{"title":"What you get","slug":"what-you-get","depth":2,"children":[]},{"title":"Setup","slug":"setup","depth":2,"children":[]},{"title":"How the workflow files work","slug":"how-the-workflow-files-work","depth":2,"children":[{"title":"Test Plan trigger","slug":"test-plan-trigger","depth":3,"children":[]},{"title":"Report generation","slug":"report-generation","depth":3,"children":[]},{"title":"Using the summary status for branch protection","slug":"using-the-summary-status-for-branch-protection","depth":3,"children":[]}]},{"title":"Testing deploy previews","slug":"testing-deploy-previews","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"spur","siteName":"Spur Documentation","title":"GitHub - Spur Documentation","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-04T21:35:29.740Z","originalFileLocation":"running-tests/cicd/github.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=\"light\";if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Spur Documentation\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"GitHub - Spur Documentation\">\u003cmeta data-mint-head property=\"og:description\" content=\"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Spur Documentation\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.spurtest.com/running-tests/cicd/github\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://spur.mintlify.site/_mintlify/api/og/v2?division=CI%2FCD\u0026amp;title=GitHub\u0026amp;description=Wire+Spur+Test+Plans+into+GitHub+Actions+to+run+automatically+on+every+pull+request%2C+report+pass%2Ffail+status+inline%2C+and+block+merges+when+tests+fail.\u0026amp;theme=454e01d6ac8800fdfeeb0e3a\u0026amp;signature=0ccd2881b817634a34b3cd9a9b5f490f7394e3fe30a29b9ada4d9d12e1261adb\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"GitHub - Spur Documentation\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://spur.mintlify.site/_mintlify/api/og/v2?division=CI%2FCD\u0026amp;title=GitHub\u0026amp;description=Wire+Spur+Test+Plans+into+GitHub+Actions+to+run+automatically+on+every+pull+request%2C+report+pass%2Ffail+status+inline%2C+and+block+merges+when+tests+fail.\u0026amp;theme=454e01d6ac8800fdfeeb0e3a\u0026amp;signature=0ccd2881b817634a34b3cd9a9b5f490f7394e3fe30a29b9ada4d9d12e1261adb\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/spur/1VX6A2Hde8UwyT8H/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Spur Documentation\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#0535dd\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.spurtest.com/running-tests/cicd/github\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/running-tests/cicd/github.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.spurtest.com/#organization\",\"name\":\"Spur Documentation\",\"url\":\"https://docs.spurtest.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/spur/cytvGy0qHI_KqMmI/logo/logo.png?fit=max\u0026auto=format\u0026n=cytvGy0qHI_KqMmI\u0026q=85\u0026s=f931455ec7ab89b4f23bea661c49b9a0\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.spurtest.com#website\",\"name\":\"Spur Documentation\",\"url\":\"https://docs.spurtest.com\",\"publisher\":{\"@id\":\"https://docs.spurtest.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.spurtest.com/running-tests/cicd/github#webpage\",\"url\":\"https://docs.spurtest.com/running-tests/cicd/github\",\"name\":\"GitHub\",\"description\":\"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.\",\"dateModified\":\"2026-11-04T21:35:29.740Z\",\"isPartOf\":{\"@id\":\"https://docs.spurtest.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.spurtest.com/running-tests/cicd/github#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.spurtest.com/running-tests/cicd/github#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Running Tests\",\"item\":\"https://docs.spurtest.com/running-tests/manual-runs\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"CI/CD\",\"item\":\"https://docs.spurtest.com/running-tests/cicd/overview\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"GitHub\",\"item\":\"https://docs.spurtest.com/running-tests/cicd/github\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.spurtest.com/running-tests/cicd/github#article\",\"headline\":\"GitHub\",\"name\":\"GitHub\",\"description\":\"Wire Spur Test Plans into GitHub Actions to run automatically on every pull request, report pass/fail status inline, and block merges when tests fail.\",\"url\":\"https://docs.spurtest.com/running-tests/cicd/github\",\"mainEntityOfPage\":{\"@id\":\"https://docs.spurtest.com/running-tests/cicd/github#webpage\"},\"dateModified\":\"2026-11-04T21:35:29.740Z\",\"publisher\":{\"@id\":\"https://docs.spurtest.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.spurtest.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Spur Documentation\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Spur Documentation","nav":{"global":null,"tabs":[{"tab":"Documentation","pages":[{"group":"Getting Started","pages":[{"title":"Welcome to Spur!","icon":"rocket","iconType":"solid","href":"/getting-started/introduction"},{"title":"Write Your First Test","icon":"pencil","iconType":"solid","href":"/getting-started/first-test"},{"title":"Web Prompting Guide","icon":"browser","iconType":"solid","href":"/getting-started/web-prompting"},{"title":"Mobile Prompting Guide","icon":"mobile-screen-button","iconType":"solid","href":"/getting-started/mobile-prompting"},{"group":"Prompt Library","icon":"book","pages":[{"title":"Overview of Prompt Library","icon":"book","iconType":"solid","href":"/getting-started/prompt-library"},{"title":"High-Level Instructions","icon":"arrow-up-wide-short","iconType":"solid","href":"/getting-started/prompt-library/high-level-instructions"},{"title":"Persona-Based Tests","icon":"user","iconType":"solid","href":"/getting-started/prompt-library/persona-based-tests"},{"title":"Exploratory Tests","icon":"compass","iconType":"solid","href":"/getting-started/prompt-library/exploratory-tests"},{"title":"Other Useful Prompts","icon":"lightbulb","iconType":"solid","href":"/getting-started/prompt-library/other-useful-prompts"}]},{"title":"Common Pitfalls When Writing Tests in Spur","sidebarTitle":"Common Pitfalls","icon":"file-slash","iconType":"solid","href":"/getting-started/common-pitfalls"},{"title":"Frequently Asked Questions","sidebarTitle":"FAQs","icon":"comment","iconType":"solid","href":"/getting-started/faq"}]},{"group":"Authoring Tests","pages":[{"group":"Test Side Peek","icon":"notes-medical","pages":[{"title":"Video to Test Generation","icon":"video","iconType":"solid","href":"/authoring-tests/test-side-peek/video-to-test"},{"title":"Script to Test Generation","icon":"scroll","iconType":"solid","href":"/authoring-tests/test-side-peek/script-to-test"},{"title":"Viewports \u0026 Device Settings","icon":"camera-viewfinder","href":"/authoring-tests/test-side-peek/viewports"},{"group":"Step Types","icon":"stairs","pages":[{"title":"Verification","icon":"check-double","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/verify"},{"group":"Browser","icon":"browser","pages":[{"title":"Open New Tab","icon":"arrow-up-right-from-square","href":"/authoring-tests/test-side-peek/step-types/browser/open-new-tab"},{"title":"Redirect","icon":"link","href":"/authoring-tests/test-side-peek/step-types/browser/redirect"},{"title":"Refresh","icon":"arrow-rotate-right","href":"/authoring-tests/test-side-peek/step-types/browser/refresh"},{"title":"Go Back","icon":"arrow-left","href":"/authoring-tests/test-side-peek/step-types/browser/go-back"},{"title":"Close the Current Tab","icon":"xmark","href":"/authoring-tests/test-side-peek/step-types/browser/close-tab"}]},{"title":"Email Inbox Steps","icon":"envelope","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/email/email-inbox"},{"title":"Extractions","icon":"magnet","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/extract"},{"title":"Javascript","icon":"code","href":"/authoring-tests/test-side-peek/step-types/javascript"},{"title":"Make an API Call","icon":"right-left","href":"/authoring-tests/test-side-peek/step-types/api-call"},{"title":"Log Step","icon":"scroll","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/log/log-assertions"},{"group":"Supported Actions","icon":"object-subtract","pages":[{"title":"Overview of Supported Actions","icon":"hand-pointer","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/actions/overview"},{"title":"Click","icon":"arrow-pointer","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/actions/click"},{"title":"Hover","icon":"computer-mouse","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/actions/hover"},{"title":"Scroll","icon":"arrows-up-down","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/actions/scroll"},{"title":"Select","icon":"square-check","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/actions/select"},{"title":"Wait","icon":"hourglass-half","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/actions/wait"},{"title":"Type","icon":"keyboard","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/actions/type"}]},{"group":"Mobile Actions","icon":"mobile-screen","pages":[{"title":"Advanced Mobile Prompting","icon":"mobile-screen","href":"/authoring-tests/test-side-peek/step-types/mobile/overview"},{"title":"Activate App","icon":"window-restore","href":"/authoring-tests/test-side-peek/step-types/mobile/activate-app"},{"title":"Restart App","icon":"arrow-rotate-right","href":"/authoring-tests/test-side-peek/step-types/mobile/restart-app"},{"title":"Shake Device","icon":"mobile-screen-button","href":"/authoring-tests/test-side-peek/step-types/mobile/shake-device"},{"title":"Flip Device","icon":"rotate","href":"/authoring-tests/test-side-peek/step-types/mobile/flip"},{"title":"Expect Toast / Expect No Toast","icon":"bell","href":"/authoring-tests/test-side-peek/step-types/mobile/expect-toast"}]},{"group":"Variables","icon":"brackets-curly","pages":[{"title":"Encrypted Variables","icon":"lock","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/variables/encrypted-variables"},{"title":"Random String Generation","icon":"shuffle","iconType":"solid","href":"/authoring-tests/test-side-peek/step-types/variables/random-string-gen"}]}]},{"icon":"gear","title":"Advanced Configurations","href":"/authoring-tests/test-side-peek/advanced-configurations"},{"title":"Login States","icon":"user-check","iconType":"solid","href":"/authoring-tests/test-side-peek/login-states"},{"title":"Upload Files","icon":"upload","href":"/authoring-tests/test-side-peek/upload-files"},{"title":"Version History","icon":"clock-rotate-left","href":"/authoring-tests/test-side-peek/version-history"}]},{"title":"Mobile Streaming","icon":"circle-play","iconType":"solid","href":"/authoring-tests/mobile-streaming"},{"title":"Preview Editor","icon":"eye","href":"/authoring-tests/preview-editor"},{"title":"Dependencies","icon":"arrows-turn-to-dots","iconType":"solid","href":"/authoring-tests/dependencies"},{"group":"Scenarios","icon":"table","pages":[{"title":"Scenario Tables","icon":"table","href":"/authoring-tests/scenarios/scenario-tables"},{"title":"Reference scenario table properties in test steps","icon":"table","href":"/authoring-tests/scenarios/scenario-properties"}]},{"group":"Environments","icon":"globe","pages":[{"icon":"globe","iconType":"solid","title":"Overview of Environments","href":"/authoring-tests/environments/overview"},{"icon":"key-skeleton-left-right","title":"Properties","href":"/authoring-tests/environments/properties"},{"title":"Full URL vs Domain","icon":"link-simple","href":"/authoring-tests/environments/web-link-vs-domain"}]},{"title":"Caching Tests","icon":"floppy-disk","iconType":"solid","href":"/authoring-tests/caching-tests"}]},{"group":"Managing Tests","pages":[{"title":"Managing Tests in Spur","icon":"sitemap","iconType":"solid","href":"/managing-tests/overview"},{"title":"Test Library","icon":"books","iconType":"solid","href":"/managing-tests/test-library"},{"title":"Test Suites: Group and Run Related Tests Together","icon":"layer-group","iconType":"solid","href":"/managing-tests/test-suite"},{"title":"Folders","icon":"folder","href":"/managing-tests/folders"},{"group":"Test Plans","icon":"list-check","pages":[{"icon":"book-open-cover","iconType":"solid","title":"Test plans: coordinate multi-suite runs","href":"/managing-tests/test-plans/overview"},{"title":"Create Test Plan","icon":"plus","href":"/managing-tests/test-plans/create-test-plan"}]},{"title":"Drafts","icon":"page","href":"/managing-tests/drafts"},{"title":"Snooze Tests","icon":"clock","href":"/managing-tests/snooze-tests"}]},{"group":"Running Tests","pages":[{"title":"Manual Runs","icon":"circle-play","iconType":"solid","href":"/running-tests/manual-runs"},{"title":"Run test plans on demand or on a schedule","icon":"list-check","iconType":"solid","href":"/running-tests/test-plans"},{"group":"CI/CD","icon":"infinity","pages":[{"title":"CI/CD","icon":"infinity","iconType":"solid","description":"Automatically run your Spur test plans on every pull request and block deployments when tests fail.","href":"/running-tests/cicd/overview"},{"title":"GitHub","icon":"github","iconType":"brands","href":"/running-tests/cicd/github"},{"group":"PR Agent","icon":"robot","pages":[{"title":"PR Agent","sidebarTitle":"Overview","icon":"robot","description":"Test your pull request with real browser checks and review the evidence before you merge.","href":"/running-tests/cicd/pr-agent"},{"title":"Set Up the PR Agent","sidebarTitle":"Setup","icon":"gear","href":"/running-tests/cicd/pr-agent-setup"},{"title":"Review and Save PR Agent Tests","sidebarTitle":"Results","icon":"bookmark","href":"/running-tests/cicd/pr-agent-results"}]},{"title":"GitLab","icon":"gitlab","iconType":"brands","href":"/running-tests/cicd/gitlab"},{"title":"Override URLs","icon":"arrow-right-arrow-left","iconType":"solid","href":"/running-tests/cicd/override-urls"}]},{"title":"Scheduling Test Plans","icon":"calendar-plus","iconType":"solid","href":"/running-tests/scheduler"},{"title":"Snoozing Tests","icon":"moon","iconType":"solid","href":"/running-tests/snoozing-tests/snooze-tests"}]},{"group":"Analyzing Tests","pages":[{"title":"Analysis Overview","icon":"magnifying-glass-chart","iconType":"solid","href":"/analysing-tests/analysis-overview"},{"group":"Spur MCP","icon":"/images/MCP/mcp_icon.svg","pages":[{"title":"Spur MCP Integration","icon":"https://mintlify.s3.us-west-1.amazonaws.com/spur/images/MCP/mcp_icon.svg","href":"/analysing-tests/mcp/spur-mcp"},{"title":"MCP Setup","icon":"wrench","href":"/analysing-tests/mcp/spur-mcp-setup"},{"title":"Discover and Run Tests","icon":"magnifying-glass","href":"/analysing-tests/mcp/spur-mcp-discover-tests"},{"title":"Fix Raised Bugs","icon":"bug","href":"/analysing-tests/mcp/spur-mcp-fix-bugs"},{"title":"Connecting With Other MCP Tools","icon":"plug","href":"/analysing-tests/mcp/spur-mcp-connecting-other-mcps"},{"title":"In-Sprint Test Generation","icon":"code","href":"/analysing-tests/mcp/spur-mcp-in-sprint-testing"},{"title":"Triaging Test Plan Failures With MCP","icon":"list-check","href":"/analysing-tests/mcp/spur-mcp-test-plans"}]},{"title":"Spur AI","icon":"sparkles","href":"/analysing-tests/spur-ai-chat"},{"title":"Using Spur AI Effectively","sidebarTitle":"Best Practices","icon":"message-bot","href":"/analysing-tests/spur-ai-chat-best-practices"},{"title":"Shareable Links","icon":"link","iconType":"solid","href":"/analysing-tests/shareable-links"},{"group":"Integrations","icon":"plug","pages":[{"title":"Integrations Overview","icon":"webhook","href":"/analysing-tests/integrations/overview"},{"title":"Jira Tickets","icon":"jira","iconType":"brands","href":"/analysing-tests/integrations/jira"},{"title":"Linear Tickets","icon":"ticket","href":"/analysing-tests/integrations/linear"},{"title":"ClickUp Tasks","icon":"list-check","href":"/analysing-tests/integrations/clickup"},{"title":"Azure DevOps Work Items","icon":"https://mintlify.s3.us-west-1.amazonaws.com/spur/images/Integrations/AzureDevOps/azure-devops-logo.svg","href":"/analysing-tests/integrations/azure-devops"},{"title":"Asana Tasks","icon":"https://mintlify.s3.us-west-1.amazonaws.com/spur/images/Integrations/Asana/asana-logo.svg","href":"/analysing-tests/integrations/asana"},{"title":"Slack Alerts","icon":"slack","iconType":"solid","href":"/analysing-tests/integrations/slack"},{"title":"Email Alerts","icon":"envelope","iconType":"solid","href":"/analysing-tests/integrations/email"},{"title":"GitHub Integration","icon":"github","iconType":"brands","href":"/analysing-tests/integrations/github"},{"title":"GitLab Integration","icon":"gitlab","iconType":"brands","href":"/analysing-tests/integrations/gitlab"}]},{"title":"Test Plan Review","icon":"scroll","href":"/analysing-tests/test-plan-review"},{"title":"Test Overview","icon":"gauge","iconType":"solid","href":"/analysing-tests/test-overview-page"},{"title":"Warning Suppression","icon":"bell-slash","iconType":"solid","href":"/analysing-tests/warning-suppression"}]},{"group":"Accessibility","pages":[{"title":"Accessibility Overview","icon":"universal-access","iconType":"solid","href":"/accessibility/overview"},{"title":"Accessibility Issues","icon":"list-check","iconType":"solid","href":"/accessibility/issues"},{"title":"Accessibility Screens","icon":"images","iconType":"solid","href":"/accessibility/screens"},{"title":"Accessibility Reports","icon":"file-lines","iconType":"solid","href":"/accessibility/reports"}]},{"group":"Additional Resources","pages":[{"title":"Spur for Data Science Teams","icon":"chart-line","href":"/additional-resources/spur-for-data-science-teams"},{"title":"Network \u0026 Console Monitoring","icon":"tower-broadcast","iconType":"solid","href":"/additional-resources/network-console-monitoring"},{"title":"IP Whitelisting","icon":"shield-check","iconType":"solid","href":"/additional-resources/ip-whitelisting"},{"title":"Signing In","icon":"right-to-bracket","iconType":"solid","href":"/additional-resources/signing-in"},{"title":"User Roles","icon":"user-shield","iconType":"solid","href":"/additional-resources/user-roles"},{"title":"Deep Links","icon":"link","iconType":"solid","href":"/additional-resources/deep-links"},{"group":"In-Sprint Test Generation","icon":"code","pages":[{"title":"In-Sprint Test Generation","icon":"code","href":"/analysing-tests/mcp/spur-mcp-in-sprint-testing"},{"group":"PR Agent","icon":"robot","pages":[{"title":"PR Agent","sidebarTitle":"Overview","icon":"robot","href":"/running-tests/cicd/pr-agent"}]}]},{"group":"SSO Providers","icon":"key","pages":[{"title":"Google SSO","href":"/additional-resources/sso-providers/google-sso"},{"title":"Azure SSO","href":"/additional-resources/sso-providers/azure-sso"}]},{"title":"Contact Us","icon":"headset","iconType":"solid","href":"/additional-resources/contact-us"}]}]},{"tab":"Changelog","pages":[{"title":"Changelog","href":"/changelog"}]},{"tab":"Press","href":"https://www.ycombinator.com/launches/LeX-spur-your-ai-qa-engineerr"},{"tab":"Community","href":"https://www.linkedin.com/company/spur-test/"}]},"basePath":"","title":"GitHub - Spur Documentation","buildId":"dpl_DTau1J5HqS9UTgVSDwGksstFWtPa","deploymentId":"dpl_DTau1J5HqS9UTgVSDwGksstFWtPa","dynamics":["07c022d89b","a74be98ba7"],"chunks":["Frame-DvzxQbD0.js","DynamicMarkdown-mQG_iQiE.js","zoom-image-lightbox-BFbLClTf.js","lightbox-handle-r17bVUz3.js"]}