diff --git a/README.md b/README.md index 0bb717e..0c83eb6 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/playwright.config.ts b/playwright.config.ts index 9e2e4a1..a2388ff 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -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", diff --git a/src/auto.ts b/src/auto.ts index 5e5119f..77497d2 100644 --- a/src/auto.ts +++ b/src/auto.ts @@ -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, }); diff --git a/src/completeTask.ts b/src/completeTask.ts index e605b55..b251a0b 100644 --- a/src/completeTask.ts +++ b/src/completeTask.ts @@ -9,7 +9,12 @@ export const completeTask = async ( page: Page, task: TaskMessage ): Promise => { - 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; diff --git a/src/sanitizeHtml.ts b/src/sanitizeHtml.ts index 62f2851..0b1e6b7 100644 --- a/src/sanitizeHtml.ts +++ b/src/sanitizeHtml.ts @@ -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 diff --git a/src/types.ts b/src/types.ts index 29b49da..8d71f06 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,9 @@ export type StepOptions = { debug?: boolean; model?: string; openaiApiKey?: string; + openaiBaseUrl?: string; + openaiDefaultQuery?: {}; + openaiDefaultHeaders?: {}; }; export type TaskMessage = { diff --git a/tests/auto.spec.ts b/tests/auto.spec.ts index 51dd338..fedb398 100644 --- a/tests/auto.spec.ts +++ b/tests/auto.spec.ts @@ -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!"); }); @@ -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"); @@ -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(); @@ -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"); }); @@ -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); @@ -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); @@ -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); @@ -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!"); });