Back to Blog

Pre-Push Smoke Testing with OpenClaw Deploy Gate

# Pre-Push Smoke Testing with OpenClaw Deploy Gate Smoke testing is a crucial aspect of the modern software development lifecycle, serving as the first line of defense against catastrophic failures. Originally a term borrowed from hardware testing—where a device is plugged in to see if it literally starts smoking—in software engineering, a smoke test ensures that the most critical functions of a program work correctly before delving into finer-grained functional testing. By catching critical issues before code changes are pushed to production or even to a shared staging environment, engineering teams can save countless hours of debugging, prevent pipeline bottlenecks, and maintain a high standard of code quality. OpenClaw Deploy Gate provides an incredibly effective, automated way to streamline this process, bridging the gap between local development and continuous integration environments. It acts as a rigid, uncompromising bouncer at the door of your central repository, ensuring your application is stable, rendering correctly, and free of glaring errors before deployment. In this comprehensive tutorial, we will cover exactly how to set up, configure, and implement pre-push smoke testing using OpenClaw Deploy Gate, moving from basic API checks to advanced headless browser DOM verification. ## The Evolution of the Git Hook and Why Pre-Push Matters Before diving into the technical prerequisites, it is important to understand why we specifically target the "pre-push" phase. Many developers are familiar with pre-commit hooks, which are excellent for running fast tasks like code formatting (Prettier), linting (ESLint), and static analysis. However, running a full test suite or a local server instance on every single commit can drastically slow down a developer's workflow, leading to frustration and the eventual bypassing of the hooks entirely. The pre-push hook strikes the perfect balance. Developers can commit their work locally as often as they like, maintaining a granular history of their progress without arbitrary delays. It is only when they attempt to share their code with the rest of the team or deploy it to a server—via `git push`—that the rigorous smoke tests are executed. This ensures that the shared repository remains pristine and that broken builds never see the light of day in your Continuous Integration (CI) pipeline. ## Prerequisites Before we dive into the setup and start writing code, ensure you have the following prerequisites fully configured on your local development machine: 1. **Basic Knowledge of Git**: Familiarity with Git commands, branching strategies, and workflows is essential. You should understand the difference between local commits, remote tracking, and how Git hooks operate within the `.git` directory structure. 2. **OpenClaw Account and CLI Installed**: You will need an active account on OpenClaw and the local CLI environment configured to access the Deploy Gate features. Deploy Gate utilizes OpenClaw's intelligent background task management to orchestrate local servers and testing agents. 3. **Node.js and npm**: Make sure you have a modern, Active LTS version of Node.js installed (e.g., v18 or v20). We will heavily utilize npm (Node Package Manager) to orchestrate our testing frameworks, scripts, and local development servers. 4. **A Sample Application**: You should have a sample application ready for testing. For the purposes of this guide, it can be a simple Express web application, a REST API service, or a front-end React/Next.js application. It simply needs to be runnable via a local command. 5. **Access to Your Repository**: Ensure you have write access to the Git repository where you will implement the smoke tests. You cannot test push hooks effectively without being able to push to a remote origin. ## Step-by-Step Instructions ### 1. Setting Up Your Project First, navigate to your application directory in your terminal and ensure you have a proper Node.js environment set up. If you are starting completely from scratch, you will need to initialize a new project and create the necessary entry points. ```bash cd /path/to/your/project npm init -y This command generates a default `package.json` file, which will serve as the central configuration hub for our testing dependencies and execution scripts. Ensure your application has a clear start script (e.g., `node server.js` or `npm start`) that successfully binds your application to a local port. ### 2. Installing Required Packages You will need a robust testing framework to perform the foundational API smoke tests. For this tutorial, we will use `Jest` due to its zero-config philosophy and excellent asynchronous testing capabilities, along with `supertest` for making HTTP assertions against our application without having to manually manage network sockets. Install these packages using npm as development dependencies: ```bash npm install --save-dev jest supertest If your application requires environmental variables (like database URIs or secret keys), you might also want to install `dotenv` to manage your local testing environment: ```bash npm install --save-dev dotenv ``` ### 3. Writing Foundational Smoke Tests Create a `tests` directory in your project root. Keeping your tests logically separated from your source code helps maintain a clean project structure. Inside this directory, create a file named `smoke.test.js`. This file will contain your baseline smoke tests. ```bash mkdir tests touch tests/smoke.test.js ``` Open `smoke.test.js` and add the following example tests. These tests instantiate your Express application and verify that the most critical routes are responding correctly. ```javascript const request = require('supertest'); const app = require('../app'); // Adjust the path based on your project structure describe('Critical Application Smoke Tests', () => { // A fundamental test to ensure the server can handle a basic GET request it('should return a 200 OK status for the primary homepage', async () => { const response = await request(app).get('/'); expect(response.statusCode).toBe(200); // We can also check that the response isn't empty expect(response.text).toBeDefined(); }); // Health check endpoints are vital for load balancers and deployment gates it('should return 200 for the internal API health check endpoint', async () => { const response = await request(app).get('/health'); expect(response.statusCode).toBe(200); expect(response.body).toHaveProperty('status', 'healthy'); }); // Test a failure condition to ensure 404s are handled gracefully it('should return a 404 for an explicitly non-existent route', async () => { const response = await request(app).get('/this-route-does-not-exist'); expect(response.statusCode).toBe(404); }); }); ``` These baseline tests ensure that your application isn't completely broken due to a syntax error, a missing dependency, or a misconfigured router. ### 4. Configuring Jest Add a dedicated test script to your `package.json` to easily execute the test suite. We will add a specific script named `test:smoke` to differentiate it from longer-running unit or integration tests. ```json "scripts": { "start": "node index.js", "test": "jest", "test:smoke": "jest tests/smoke.test.js --detectOpenHandles --forceExit" } ``` The `--detectOpenHandles` and `--forceExit` flags are incredibly useful in CI and hook environments to ensure that Jest doesn't hang indefinitely if your application leaves a database connection or network socket open after the tests complete. ### 5. Setting Up OpenClaw Deploy Gate While Jest covers our API and backend routes, modern web applications require more rigorous validation. OpenClaw Deploy Gate acts as a pre-deploy validation gate specifically designed for web projects. It goes far beyond simple API checks. When configured, OpenClaw Deploy Gate automatically: 1. Starts your application locally in an isolated background process. 2. Runs headless browser instances (via Chromium) against your key URLs. 3. Checks for hidden JavaScript console errors (which standard API tests miss). 4. Verifies that critical DOM elements (like login buttons, navigation bars, or data tables) successfully render on the page. To initialize Deploy Gate in your repository, you need to create a configuration file at the root of your project. ```bash touch deploy-gate.config.json ``` Populate it with the following configuration: ```json { "startCommand": "npm start", "port": 3000, "readyTimeout": 15000, "urls": [ { "path": "/", "expectedDomElements": ["#main-nav", ".hero-section"], "allowConsoleWarnings": true, "allowConsoleErrors": false }, { "path": "/login", "expectedDomElements": ["form#login-form", "button[type='submit']"] } ] } ``` This instructs the OpenClaw Deploy Gate skill to boot your app, wait up to 15 seconds for port 3000 to bind, and then navigate to the root and `/login` paths using a headless browser, failing the test if any console errors are thrown or if the expected elements fail to mount to the DOM. ### 6. Creating a Pre-Push Hook Now you need to wire everything together by creating a pre-push hook in your Git repository. Git hooks are simply bash scripts executed by Git before specific events occur. Create a new file named `pre-push` in the `.git/hooks` directory: ```bash touch .git/hooks/pre-push chmod +x .git/hooks/pre-push # This step is crucial; the script MUST be executable ``` Open the `pre-push` file and add the following contents to chain together both your standard Jest smoke tests and the OpenClaw Deploy Gate headless browser validation: ```bash #!/bin/bash echo "================================================================" echo "🚀 Initiating Pre-Push Validation Sequence..." echo "================================================================" # Step 1: Run foundational API smoke tests echo "Phase 1: Running Jest API Smoke Tests..." npm run test:smoke # Capture the exit code of Jest JEST_RESULT=$? if [ $JEST_RESULT -ne 0 ]; then echo "❌ API Smoke tests failed! Please fix the backend errors before pushing." echo "Push aborted." exit 1 fi echo "✅ API Smoke tests passed." # Step 2: Run OpenClaw Deploy Gate for UI/Console validation echo "Phase 2: Booting OpenClaw Deploy Gate Headless Validation..." openclaw run deploy-gate --config=deploy-gate.config.json # Capture the exit code of Deploy Gate GATE_RESULT=$? if [ $GATE_RESULT -ne 0 ]; then echo "❌ OpenClaw Deploy Gate validation failed!" echo "Review the headless browser logs above for DOM missing elements or JS console errors." echo "Push aborted." exit 1 fi echo "✅ OpenClaw Deploy Gate validation passed." echo "🎉 All smoke tests passed successfully. Proceeding with git push to remote repository." exit 0 ``` ### 7. Testing Your Setup Now that everything is robustly configured, you must verify that the gatekeeper functions correctly. 1. **Test the Happy Path**: Make a benign change to your application (e.g., updating a README file or a text string). 2. **Stage and commit** your changes: ```bash git add . git commit -m "chore: test pre-push smoke validation" ``` 3. **Push** your changes: ```bash git push origin main ``` Watch your terminal. You should see Git pause, output the logs for Jest, followed by the headless browser initialization from Deploy Gate, and finally the successful push to your remote repository. 4. **Test the Failure Path (Crucial)**: Now, intentionally break your application. Rename the `#login-form` ID in your HTML to something else, or throw a `new Error("broken")` in your client-side JavaScript bundle. Commit the change, and attempt to push. The hook **must** block the push and return an error. ### 8. Troubleshooting Tips Even with a perfect setup, local environments can be tricky. Here are advanced troubleshooting strategies: - **Tests are Failing Intermittently (Flaky Tests)**: If Deploy Gate sometimes passes and sometimes fails, you likely have a race condition. Your application might take longer to connect to its database than the `readyTimeout` allows. Increase the timeout in `deploy-gate.config.json` or ensure your application delays binding to the port until all async setup operations (like DB connections) are fully resolved. - **Hook Not Executing At All**: Confirm that the `pre-push` hook is executable. You can set the executable permission using `chmod +x .git/hooks/pre-push`. Also, if you cloned the repository fresh, hooks are *not* included in git clones. You must set them up locally or use a package like Husky to auto-install them for your team. - **Node or Jest Not Found in Hook**: Git GUI clients (like SourceTree, GitKraken, or GitHub Desktop) often run in isolated environments and may not inherit your terminal's `PATH`. If your hook fails in a GUI but passes in the terminal, you need to load your Node environment managers (like `nvm` or `asdf`) explicitly at the top of your `pre-push` bash script. - **Bypassing the Hook in Emergencies**: If you have a legitimate, absolute emergency and need to push a hotfix that skips tests, you can append `--no-verify` to your git command (e.g., `git push origin main --no-verify`). **Use this sparingly and only when absolutely necessary.** ## Best Practices for Maintaining Smoke Tests Implementing the pre-push hook is only step one. Maintaining a healthy testing culture requires discipline. First, **keep smoke tests incredibly fast.** A pre-push hook should execute in less than 60 seconds. If developers are waiting 5 minutes for a push to complete, they will start using `--no-verify` out of pure frustration. Move deep regression testing, end-to-end user flows, and exhaustive database state testing to your CI/CD pipeline (like GitHub Actions or GitLab CI) that runs *after* the push. Second, **ensure deterministic test environments.** If your smoke tests rely on a local development database, ensure that the data state is mocked or seeded identically every time. Tests that pass on your machine but fail on a coworker's machine due to local database differences defeat the purpose of the gate. Use tools like SQLite for in-memory DB testing during the hook phase to guarantee isolation. Finally, **review and update the DOM element checks regularly.** As your application's UI evolves, classes and IDs will change. OpenClaw Deploy Gate will dutifully block pushes if a developer renames `#main-nav` to `.primary-navigation` without updating the `deploy-gate.config.json`. Make updating the Deploy Gate config a mandatory part of your pull request review process. ## Frequently Asked Questions (FAQ) **1. Why should I use a pre-push hook instead of just relying on my CI/CD pipeline like GitHub Actions?** While CI/CD pipelines are essential, they are reactive. A developer pushes broken code, the pipeline spins up a runner (which costs money and takes time), runs the tests, and fails 10 minutes later. The repository is now in a broken state until a fix is pushed. Pre-push hooks are proactive. They catch the glaring errors locally, saving CI runner minutes, keeping the remote branch green, and giving the developer immediate, context-rich feedback while the code is still fresh in their mind. **2. How long is too long for a pre-push smoke test?** As a general rule, a pre-push hook should run in under 60 seconds, with an ideal target of 15-30 seconds. Remember that developers may push multiple times an hour. If the hook takes 3 minutes, you are severely degrading developer velocity. Keep it restricted to app startup, critical API checks, and basic DOM rendering. **3. Does OpenClaw Deploy Gate require Docker or complex container orchestration?** No. OpenClaw Deploy Gate is designed to be lightweight. It uses your local Node environment to start the app and leverages a local installation of Chromium/Puppeteer/Playwright to perform the headless DOM checks. It avoids the heavy overhead of spinning up Docker containers just to perform a smoke test, ensuring execution remains lightning fast. **4. What if my application requires a database or third-party APIs to boot up?** For pre-push smoke tests, it is highly recommended to use environment variables to run your application in a "mocked" or "stubbed" state. You do not want your local tests to fail because a third-party API is experiencing an outage. Configure your app to bypass external dependencies during smoke tests, or use mocking libraries to intercept those network requests. **5. How do I enforce these hooks across my entire engineering team?** By default, the `.git/hooks` directory is not committed to source control. To enforce hooks across a team, you should use a package like Husky (`npm install husky --save-dev`). Husky allows you to define your hooks in your `package.json` or a `.husky` directory, which *is* committed to source control. When developers run `npm install`, Husky automatically wires up the Git hooks on their local machine. ## Conclusion Implementing pre-push smoke testing with OpenClaw Deploy Gate is a transformative step for any engineering team looking to improve code quality and deployment confidence. By combining rapid API validations with robust, headless browser DOM checks, you create an impenetrable barrier against broken code entering your repository. While it requires a small upfront investment in configuration and team discipline, the return on investment is massive. You will experience fewer broken staging environments, lower CI/CD compute costs, faster debugging cycles, and the peace of mind knowing that every commit pushed to your remote repository represents a fundamentally sound, functioning application. Treat your pre-push hooks not as a hindrance, but as a critical safety net empowering you to move faster without breaking things. ### Related Topics: - [Continuous Integration with OpenClaw](https://stormap.ai/documentation/ci): Learn how to extend your local Deploy Gate validations into a fully automated CI/CD pipeline that scales with your organization. - [Automating Your Testing Workflow](https://stormap.ai/documentation/automation): Discover deeper strategies for using Husky, lint-staged, and other automation tools to streamline the developer experience. - [Advanced Testing Techniques in Jest](https://stormap.ai/documentation/jest): Master mocking, spying, and asynchronous testing techniques to build a bulletproof local testing suite.