functions.e2e.ts•4.08 kB
/// <reference types="../extensions.d.ts" />
import { generateText, type ToolCallUnion, type ToolSet } from 'ai';
import { codeBlock } from 'common-tags';
import { describe, expect, test } from 'vitest';
import { createOrganization, createProject } from '../mocks.js';
import { join } from 'node:path/posix';
import { getTestModel, setup } from './utils.js';
describe('edge function e2e tests', () => {
  test('deploys an edge function', async () => {
    const { client } = await setup();
    const model = getTestModel();
    const org = await createOrganization({
      name: 'My Org',
      plan: 'free',
      allowed_release_channels: ['ga'],
    });
    const project = await createProject({
      name: 'todos-app',
      region: 'us-east-1',
      organization_id: org.id,
    });
    const toolCalls: ToolCallUnion<ToolSet>[] = [];
    const tools = await client.tools();
    const { text } = await generateText({
      model,
      tools,
      messages: [
        {
          role: 'system',
          content:
            'You are a coding assistant. The current working directory is /home/user/projects/todos-app.',
        },
        {
          role: 'user',
          content: `Deploy an edge function to project with ref ${project.id} that returns the current time in UTC.`,
        },
      ],
      maxSteps: 3,
      async onStepFinish({ toolCalls: tools }) {
        toolCalls.push(...tools);
      },
    });
    expect(toolCalls).toContainEqual(
      expect.objectContaining({ toolName: 'deploy_edge_function' })
    );
    await expect(text).toMatchCriteria(
      'Confirms the successful deployment of an edge function that will return the current time in UTC. It describes steps to test the function.'
    );
  });
  test('modifies an edge function', async () => {
    const { client } = await setup();
    const model = getTestModel();
    const org = await createOrganization({
      name: 'My Org',
      plan: 'free',
      allowed_release_channels: ['ga'],
    });
    const project = await createProject({
      name: 'todos-app',
      region: 'us-east-1',
      organization_id: org.id,
    });
    const code = codeBlock`
      Deno.serve(async (req: Request) => {
        return new Response('Hello world!', { headers: { 'Content-Type': 'text/plain' } })
      })
    `;
    const edgeFunction = await project.deployEdgeFunction(
      {
        name: 'hello-world',
        entrypoint_path: 'index.ts',
      },
      [
        new File([code], 'index.ts', {
          type: 'application/typescript',
        }),
      ]
    );
    const toolCalls: ToolCallUnion<ToolSet>[] = [];
    const tools = await client.tools();
    const { text } = await generateText({
      model,
      tools,
      messages: [
        {
          role: 'system',
          content:
            'You are a coding assistant. The current working directory is /home/user/projects/todos-app.',
        },
        {
          role: 'user',
          content: `Change my edge function (project id ${project.id}) to replace "world" with "Earth".`,
        },
      ],
      maxSteps: 4,
      async onStepFinish({ toolCalls: tools }) {
        toolCalls.push(...tools);
      },
    });
    expect(toolCalls).toHaveLength(3);
    expect(toolCalls[0]).toEqual(
      expect.objectContaining({ toolName: 'list_edge_functions' })
    );
    expect(toolCalls[1]).toEqual(
      expect.objectContaining({ toolName: 'get_edge_function' })
    );
    expect(toolCalls[2]).toEqual(
      expect.objectContaining({ toolName: 'deploy_edge_function' })
    );
    await expect(text).toMatchCriteria(
      'Confirms the successful modification of an Edge Function.'
    );
    expect(edgeFunction.files).toHaveLength(1);
    expect(edgeFunction.files[0].name).toBe(
      join(edgeFunction.pathPrefix, 'index.ts')
    );
    await expect(edgeFunction.files[0].text()).resolves.toEqual(codeBlock`
      Deno.serve(async (req: Request) => {
        return new Response('Hello Earth!', { headers: { 'Content-Type': 'text/plain' } })
      })
    `);
  });
});