Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Azure OpenAI #29

Merged
merged 7 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,45 @@ test("auto Playwright example", async ({ page }) => {
expect(searchInputHasHeaderText).toBe(true);
});
```
### Setup with Azure OpenAI

Include the StepOptions type with the values needed for connecting to Azure OpenAI.

```ts
import { test, expect } from "@playwright/test";
import { auto } from "auto-playwright";
import { StepOptions } from "../src/types";

const apiKey = "apikey";
const resource = "azure-resource-name";
const model = "model-deployment-name";

const options: StepOptions = {
model: model,
openaiApiKey: apiKey,
openaiBaseUrl: `https://${resource}.openai.azure.com/openai/deployments/${model}`,
openaiDefaultQuery: { 'api-version': "2023-07-01-preview" },
openaiDefaultHeaders: { 'api-key': apiKey }
};

test("auto Playwright example", async ({ page }) => {
await page.goto("/");

// `auto` can query data
// In this case, the result is plain-text contents of the header
const headerText = await auto("get the header text", { page, test }, options);

// `auto` can perform actions
// In this case, auto will find and fill in the search text input
await auto(`Type "${headerText}" in the search box`, { page, test }, options);

// `auto` can assert the state of the website
// In this case, the result is a boolean outcome
const searchInputHasHeaderText = await auto(`Is the contents of the search box equal to "${headerText}"?`, { page, test }, options);

expect(searchInputHasHeaderText).toBe(true);
});
```

## Usage

Expand Down
1 change: 1 addition & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from "@playwright/test";

export default defineConfig({
timeout: 90000,
webServer: {
command: "npm run start",
url: "http://127.0.0.1:3000",
Expand Down
3 changes: 3 additions & 0 deletions src/auto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ async function runTask(
model: options.model ?? "gpt-4-1106-preview",
debug: options.debug ?? false,
openaiApiKey: options.openaiApiKey,
openaiBaseUrl: options.openaiBaseUrl,
openaiDefaultQuery: options.openaiDefaultQuery,
openaiDefaultHeaders: options.openaiDefaultHeaders,
}
: undefined,
});
Expand Down
7 changes: 6 additions & 1 deletion src/completeTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ export const completeTask = async (
page: Page,
task: TaskMessage
): Promise<TaskResult> => {
const openai = new OpenAI({ apiKey: task.options?.openaiApiKey });
const openai = new OpenAI({
apiKey: task.options?.openaiApiKey,
baseURL: task.options?.openaiBaseUrl,
defaultQuery: task.options?.openaiDefaultQuery,
defaultHeaders: task.options?.openaiDefaultHeaders,
});

let lastFunctionResult: null | { errorMessage: string } | { query: string } =
null;
Expand Down
2 changes: 1 addition & 1 deletion src/sanitizeHtml.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as sanitize from "sanitize-html";
import sanitize from "sanitize-html";

/**
* The reason for sanitization is because OpenAI does not need all of the HTML tags
Expand Down
3 changes: 3 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export type StepOptions = {
debug?: boolean;
model?: string;
openaiApiKey?: string;
openaiBaseUrl?: string;
openaiDefaultQuery?: {};
openaiDefaultHeaders?: {};
};

export type TaskMessage = {
Expand Down
25 changes: 15 additions & 10 deletions tests/auto.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { expect, test } from "@playwright/test";
import { auto } from "../src/auto";

const options = undefined;

test("executes query", async ({ page }) => {
await page.goto("/");

const headerText = await auto("get the header text", { page, test });
const headerText = await auto("get the header text", { page, test }, options);

expect(headerText).toBe("Hello, Rayrun!");
});
Expand All @@ -15,7 +17,7 @@ test("executes query using locator_evaluate", async ({ page }) => {
const headerText = await auto("get the first letter of the header text", {
page,
test,
});
}, options);

// TODO assert that we are using locator_evaluate to get the first letter
expect(headerText).toBe("H");
Expand All @@ -24,7 +26,7 @@ test("executes query using locator_evaluate", async ({ page }) => {
test("executes action", async ({ page }) => {
await page.goto("/");

await auto(`Type "foo" in the search box`, { page, test });
await auto(`Type "foo" in the search box`, { page, test }, options);

await page.pause();

Expand All @@ -37,7 +39,7 @@ test("executes click", async ({ page }) => {
await auto("Click the button until the counter value is equal to 2", {
page,
test,
});
}, options);

await expect(page.getByTestId("current-count")).toHaveText("2");
});
Expand All @@ -47,7 +49,8 @@ test("asserts (toBe)", async ({ page }) => {

const searchInputHasHeaderText = await auto(
`Is the contents of the header equal to "Hello, Rayrun!"?`,
{ page, test }
{ page, test },
options
);

expect(searchInputHasHeaderText).toBe(true);
Expand All @@ -58,7 +61,8 @@ test("asserts (not.toBe)", async ({ page }) => {

const searchInputHasHeaderText = await auto(
`Is the contents of the header equal to "Flying Donkeys"?`,
{ page, test }
{ page, test },
options
);

expect(searchInputHasHeaderText).toBe(false);
Expand All @@ -67,13 +71,14 @@ test("asserts (not.toBe)", async ({ page }) => {
test("executes query, action and assertion", async ({ page }) => {
await page.goto("/");

const headerText = await auto("get the header text", { page, test });
const headerText = await auto("get the header text", { page, test }, options);

await auto(`type "${headerText}" in the search box`, { page, test });
await auto(`type "${headerText}" in the search box`, { page, test }, options);

const searchInputHasHeaderText = await auto(
`is the contents of the search box equal to "${headerText}"?`,
{ page, test }
{ page, test },
options
);

expect(searchInputHasHeaderText).toBe(true);
Expand All @@ -82,7 +87,7 @@ test("executes query, action and assertion", async ({ page }) => {
test("runs without test parameter", async ({ page }) => {
await page.goto("/");

const headerText = await auto("get the header text", { page });
const headerText = await auto("get the header text", { page }, options);

expect(headerText.query).toBe("Hello, Rayrun!");
});
Loading