Skip to content

Commit

Permalink
Merge pull request #29 from wix-incubator/copilot-doc-site
Browse files Browse the repository at this point in the history
docs: create Docusaurus documentation site for Copilot by Detox
  • Loading branch information
asafkorem authored Jan 3, 2025
2 parents 6f8c73f + 97f414e commit fcdbd52
Show file tree
Hide file tree
Showing 55 changed files with 19,153 additions and 1 deletion.
25 changes: 25 additions & 0 deletions .idea/watcherTasks.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
echo "20" > .nvmrc
lts/jod
20 changes: 20 additions & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Dependencies
/node_modules

# Production
/build

# Generated files
.docusaurus
.cache-loader

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
43 changes: 43 additions & 0 deletions website/docs/API/basic-interface-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
id: basic-interface-overview
title: Basic Interface Overview
sidebar_label: Basic Interface Overview
sidebar_position: 1
---

# Basic Interface Overview
The Copilot class serves as the core of the testing process, allowing seamless interaction between natural language prompts and your testing framework. Below is an overview of its main lifecycle commands that help control the test flow:

## 1. `init(config: Config): void`
The init method initializes the Copilot instance with the provided configuration. This must be called before using Copilot to ensure it is set up with the necessary framework drivers and prompt handlers.

```typescript
Copilot.init(config);
```

## 2. `start(): void`
The start method begins a new test flow, resetting previous steps and clearing any temporary cache. It must be called before performing any steps in the test.

```typescript
copilot.start();
```
Note: Calling start after an active test flow has already been started will result in an error. Be sure to call end() before starting a new flow.

## 3. `performStep(step: string): Promise<any>`
The performStep method allows Copilot to perform a test step based on a natural language prompt. The input step is parsed and evaluated by Copilot, interacting with the underlying framework to execute the corresponding action.

```typescript
const result = await copilot.performStep("Click the login button");
```
If Copilot is not running (i.e., start() has not been called), an error will be thrown.

## 4. `end(saveToCache: boolean = true): void`
The end method concludes the test flow. It can optionally save temporary data to the main cache, ensuring any relevant information is retained for future tests.

```typescript
copilot.end(true); // Save to cache
```
Note: The end method should be called when the test flow is complete, and start() must be invoked again before starting a new test.

## Error Handling
If any method is called out of sequence, such as trying to perform steps without starting Copilot, or attempting to start Copilot while it is already running, the class will throw a CopilotError. This ensures that the test flow is controlled and prevents inconsistent states.
138 changes: 138 additions & 0 deletions website/docs/API/framework-driver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
id: framework-driver
title: Framework Driver
sidebar_label: Framework Driver
sidebar_position: 3
---

# Framework Driver

In this section, we will explain how to implement custom drivers for different testing frameworks in **Copilot by Detox**. A **Framework Driver** is a crucial component that ensures **Copilot** remains agnostic to the underlying testing framework, allowing it to work seamlessly with different frameworks like Detox, Jest, Mocha, etc.

## What is a Framework Driver?

A **Framework Driver** provides an abstraction layer between **Copilot** and the underlying testing framework. It defines the necessary methods to interact with the testing framework's API and potentially supports features such as taking snapshots of the app's UI and capturing the view hierarchy.

By implementing a custom driver, you enable **Copilot** to communicate with your chosen testing framework, making it flexible and adaptable to a variety of testing environments.

### TestingFrameworkDriver Interface

The `TestingFrameworkDriver` interface defines the essential methods that a driver should implement:

- **`captureSnapshotImage`**: Takes a snapshot of the current screen and returns the path to the saved image. If the driver does not support snapshot functionality, it should return `undefined`.
- **`captureViewHierarchyString`**: Returns the current view hierarchy in a string representation, which helps the AI understand the structure of the app’s UI.
- **`apiCatalog`**: Provides access to the available methods of the testing framework's API, such as matchers and actions.

Here’s the interface definition for the driver:

```typescript
/**
* Interface for the testing driver that will be used to interact with the underlying testing framework.
*/
export interface TestingFrameworkDriver {
/**
* Takes a snapshot of the current screen and returns the path to the saved image.
* If the driver does not support image, return undefined.
*/
captureSnapshotImage: () => Promise<string | undefined>;

/**
* Returns the current view hierarchy in a string representation.
*/
captureViewHierarchyString: () => Promise<string>;

/**
* The available guides methods of the testing framework.
*/
apiCatalog: TestingFrameworkAPICatalog;
}
```
### Example: Detox Testing Framework Driver

The following example demonstrates **part of the implementation** of a **Framework Driver** for the **Detox** testing framework. This snippet focuses on integrating core functionality like matchers, actions, and snapshot capabilities:

```typescript
const jestExpect = require('expect').default;
const detox = require('../..');

const detoxCopilotFrameworkDriver = {
apiCatalog: {
context: { ...detox, jestExpect },
categories: [
{
title: 'Matchers',
items: [
{
signature: 'by.id(id: string)',
description: 'Matches elements by their test ID.',
example: "element(by.id('loginButton'))",
guidelines: ['Use test IDs (accessibility identifiers) to uniquely identify elements. This is the best-practice matcher.'],
},
{
signature: 'by.text(text: string)',
description: 'Matches elements by their text (value).',
example: "element(by.text('Login'))",
guidelines: ['Prefer test IDs over text matchers when possible.'],
},
// Additional matchers can be added here...
],
},
{
title: 'Actions',
items: [
{
signature: 'tap(point?: Point2D)',
description: 'Simulates tap on an element.',
example: "await element(by.id('loginButton')).tap();",
},
{
signature: 'longPress(point?: Point2D, duration?: number)',
description: 'Simulates long press on an element.',
example: "await element(by.id('menuItem')).longPress();",
guidelines: ['Tapping on edges of elements might work better when adding a small offset to the point.'],
},
// Additional actions can be added here...
],
},
],
},
// Example method implementations:
captureSnapshotImage: async () => {
try {
const screenshot = await detox.device.takeScreenshot();
return screenshot;
} catch (error) {
console.error('Error capturing snapshot:', error);
return undefined;
}
},

captureViewHierarchyString: async () => {
try {
const hierarchy = await detox.device.getUIHierarchy();
return hierarchy;
} catch (error) {
console.error('Error capturing view hierarchy:', error);
return '';
}
},
};

module.exports = detoxCopilotFrameworkDriver;
```
### Optional Support for Snapshot

The **Framework Driver** can optionally support snapshot functionality. If the underlying framework supports capturing screenshots or images of the app, this feature can be implemented in the `captureSnapshotImage` method. If the driver does not support snapshots, it should return `undefined`.

### Referencing Relevant Types

The types related to the **Testing Framework Driver** can be found in the source code files under the following locations:

- `TestingFrameworkDriver` interface is defined in the `src/types` folder.
- `TestingFrameworkAPICatalog` provides information about the available API methods and can also be found in the same folder.

## Conclusion

By implementing a **Framework Driver**, **Copilot by Detox** can work with any testing framework, giving users flexibility in their testing setup. For more detailed instructions, you can refer to the relevant types and source code for guidance.

If you are interested in contributing or have any suggestions for improving the **Framework Driver** system, check out the open tasks on our [GitHub repository](https://github.com/wix-incubator/detox-copilot/issues).
116 changes: 116 additions & 0 deletions website/docs/API/prompt-handler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
id: prompt-handler
title: Prompt Handler
sidebar_label: Prompt Handler
sidebar_position: 2
---

# Prompt Handler

In this section, we will cover how to implement a **Prompt Handler** to interact with AI services, such as OpenAI, in the context of **Copilot by Detox**.

## What is a Prompt Handler?

A **Prompt Handler** is responsible for sending a prompt to an AI service and receiving the response. It may also handle the inclusion of additional context, such as a snapshot image, to enhance the AI's understanding of the app's UI state. Implementing a prompt handler allows **Copilot** to generate intelligent test scripts based on natural language commands.

## How to Write a Prompt Handler

A **Prompt Handler** follows a defined interface, which ensures it can communicate with any AI service in a standardized way.

### PromptHandler Interface

The `PromptHandler` interface includes the following methods:

- **`runPrompt`**: Sends a prompt to the AI service and returns the generated response.
- **`isSnapshotImageSupported`**: Checks if the AI service supports snapshot images to provide additional context.

Here’s an example of the `PromptHandler` interface:

```typescript
/**
* Interface for the prompt handler that will be used to interact with the AI service (e.g. OpenAI).
*/
export interface PromptHandler {
/**
* Sends a prompt to the AI service and returns the response.
* @param prompt The prompt to send to the AI service.
* @param image Optional path to the image to upload to the AI service that captures the current UI state.
* @returns The response from the AI service.
*/
runPrompt: (prompt: string, image?: string) => Promise<string>;

/**
* Checks if the AI service supports snapshot images for context.
*/
isSnapshotImageSupported: () => boolean;
}
```

### Example: Implementing the Prompt Handler for Sonnet

```typescript
const axios = require('axios');
const fs = require('fs').promises;

class PromptHandler {
// Upload an image to the AI service
async uploadImage(imagePath) {
const image = await fs.readFile(imagePath);

try {
const response = await axios.post('https://bo.wix.com/mobile-infra-ai-services/v1/image-upload', {
image,
});

const imageUrl = response.data.url;
if (!imageUrl) {
throw new Error('Cannot find uploaded URL, got response:', response.data);
}

return imageUrl;
} catch (error) {
console.error('Error while uploading image:', error);
throw error;
}
}

// Run the prompt and return the generated text
async runPrompt(prompt, image) {
if (!image) {
throw new Error('Image is required');
}

const imageUrl = await this.uploadImage(image);

try {
const response = await axios.post('https://bo.wix.com/mobile-infra-ai-services/v1/prompt', {
prompt,
model: 'SONNET_3_5',
ownershipTag: 'Detox OSS',
project: 'Detox OSS',
images: [imageUrl]
});

const generatedText = response.data.generatedTexts[0];
if (!generatedText) {
throw new Error('Failed to generate text, got response:', response.data);
}

return generatedText;
} catch (error) {
console.error('Error running prompt:', error);
throw error;
}
}

// Check if snapshot images are supported
isSnapshotImageSupported() {
return true;
}
}

module.exports = PromptHandler;
```

## Open Tasks For Contributors
If you're interested in contributing to Copilot by Detox and adding new prompt handlers or improving the existing ones, check out the open tasks on our [GitHub repository](https://github.com/wix-incubator/detox-copilot/issues).
Loading

0 comments on commit fcdbd52

Please sign in to comment.