Skip to content

di-sukharev/AI-TDD

Repository files navigation

aitdd logo

AI + TDD

Follow the bird

GPT powered CLI for TDD

You write the test — GPT writes the code until it passes the test ✅

Prompting GPT with a test suite makes it write code impressively accurate


Setup

AITDD runs on Bun, make sure you first install the latest Bun version.

  1. Install AITDD globally as a CLI:

    curl -sSL https://raw.githubusercontent.com/di-sukharev/AI-TDD/master/install.sh | bash
  2. Get your API key from OpenAI. Make sure you add payment details, so API works.

  3. Set the key to AITDD config:

    aitdd config set OPENAI_API_KEY <your_api_key>

    Your api key is stored locally in ~/.aitdd/config config file and is not stored anywhere in any other way.

  4. Set the command to run the tests:

    aitdd config set RUN_TESTS "npm run test"

Your api key is stored locally in ~/.aitdd/config config file and is not stored anywhere in any other way.

Example

Here is a frontend test suite written in Jest + Testing Library. Yes, AITDD easily passes even frontend tests:

import React from "react";
import { rest } from "msw";
import { setupServer } from "msw/node";
import { render, fireEvent, waitFor, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Fetch from "../fetch";

const server = setupServer(
  rest.get("/greeting", (req, res, ctx) => {
    return res(ctx.json({ greeting: "hello there" }));
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test("loads and displays greeting", async () => {
  render(<Fetch url="/greeting" />);

  fireEvent.click(screen.getByText("Load Greeting"));

  await waitFor(() => screen.getByRole("heading"));

  expect(screen.getByRole("heading")).toHaveTextContent("hello there");
  expect(screen.getByRole("button")).toBeDisabled();
});

test("handles server error", async () => {
  server.use(
    rest.get("/greeting", (req, res, ctx) => {
      return res(ctx.status(500));
    })
  );

  render(<Fetch url="/greeting" />);

  fireEvent.click(screen.getByText("Load Greeting"));

  await waitFor(() => screen.getByRole("alert"));

  expect(screen.getByRole("alert")).toHaveTextContent("Oops, failed to fetch!");
  expect(screen.getByRole("button")).not.toBeDisabled();
});

Ready? Here is the code generated by AITDD (GPT-4) to pass the test:

import React, { useState } from "react";

function Fetch({ url }) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  async function fetchData() {
    setLoading(true);
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error("Failed to fetch");
      const data = await response.json();
      setData(data.greeting);
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div>
      {data && <h1 role="heading">{data}</h1>}
      {error && <div role="alert">{error}</div>}
      <button onClick={fetchData} disabled={loading}>
        Load Greeting
      </button>
    </div>
  );
}

export default Fetch;

Usage

You can call aitdd like this:

aitdd run

Payments

You pay for your own requests to OpenAI API. AITDD uses latest GPT model by default, check it's pricing. Maximum response tokens are set to 2000, you can adjust it via ait config set maxTokens=<number>.

I couldn't manage ChatGPT model to solve the problem. I tried to few shot it with a response example, it doesn't understand what I want. If you want to try manage it via ChatGPT — test it and open a PR 🚀