Skip to content

Commit 03337a9

Browse files
committed
wip: setting up initial tests to get to the app.
1 parent 969a308 commit 03337a9

File tree

9 files changed

+154
-69
lines changed

9 files changed

+154
-69
lines changed

playwright/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ node_modules/
55
/playwright-report/
66
/blob-report/
77
/playwright/.cache/
8+
.auth/

playwright/fixtures/LoginPage.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { Page, Locator, BrowserContext } from "@playwright/test";
2+
import { expect } from "@playwright/test";
3+
const apiKey = process.env.REFACT_API_KEY ?? "test-api-key";
4+
5+
// Create a mock response that matches GoodPollingResponse type
6+
7+
function parseOrElse<T>(str: string, fallback: T): T {
8+
try {
9+
const data = JSON.parse(str);
10+
return data as T;
11+
} catch {
12+
return fallback;
13+
}
14+
}
15+
const StubResponse = {
16+
retcode: "OK",
17+
account: "test@example.com",
18+
inference_url: "https://inference.smallcloud.ai/",
19+
inference: "PRO",
20+
metering_balance: 1000,
21+
questionnaire: true, // TODO: this disables the survey
22+
refact_agent_max_request_num: 100,
23+
refact_agent_request_available: null,
24+
secret_key: apiKey,
25+
tooltip_message: "Welcome to Refact!",
26+
login_message: "You are now logged in",
27+
"longthink-filters": [],
28+
"longthink-functions-today": {},
29+
"longthink-functions-today-v2": {},
30+
};
31+
export class LoginPage {
32+
constructor(public readonly page: Page) {}
33+
34+
async doLogin(url?: string, openSurvey = false) {
35+
// Set up route interception before navigating;
36+
const mockResponse = {
37+
...StubResponse,
38+
questionnaire: !openSurvey,
39+
};
40+
await this.page
41+
.context()
42+
.route(
43+
"https://www.smallcloud.ai/v1/streamlined-login-recall-ticket",
44+
async (route) => {
45+
// Return our mock response
46+
await route.fulfill({
47+
status: 200,
48+
contentType: "application/json",
49+
body: JSON.stringify(mockResponse),
50+
});
51+
}
52+
);
53+
54+
// TODO: hard coded for now
55+
await this.page.goto(url || "http://localhost:5173/");
56+
57+
await expect(
58+
this.page.getByRole("heading", { name: "Login to Refact.ai" })
59+
).toBeVisible({ timeout: 10000 });
60+
61+
await this.page.waitForSelector('button:has-text("Continue with Google")');
62+
63+
await this.page.click('button:has-text("Continue with Google")');
64+
65+
await this.page.waitForLoadState("networkidle");
66+
67+
await expect(this.page).toHaveURL("http://localhost:5173/");
68+
// wait for route to have been Called
69+
await expect(
70+
this.page.getByRole("heading", { name: "Login to Refact.ai" })
71+
).not.toBeVisible({ timeout: 10000 });
72+
}
73+
}

playwright/fixtures/Survey.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// TODO: handle the survey if it shows up.
2+
3+
import { Page } from "@playwright/test";
4+
5+
class Survey {
6+
constructor(public readonly page: Page) {}
7+
8+
dismissSurvey() {}
9+
}

playwright/fixtures/TourPage.ts

Whitespace-only changes.

playwright/fixtures/index.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { test as baseTest } from "@playwright/test";
2+
import fs from "fs";
3+
import path from "path";
4+
import { LoginPage } from "./LoginPage";
5+
6+
export * from "@playwright/test";
7+
export const test = baseTest.extend<
8+
{
9+
loginPage: LoginPage;
10+
},
11+
{ workerStorageState: string }
12+
>({
13+
// Use the same storage state for all tests in this worker.
14+
storageState: ({ workerStorageState }, use) => use(workerStorageState),
15+
16+
// Authenticate once per worker with a worker-scoped fixture.
17+
workerStorageState: [
18+
async ({ browser }, use) => {
19+
// Use parallelIndex as a unique identifier for each worker.
20+
const id = test.info().parallelIndex;
21+
const fileName = path.resolve(
22+
test.info().project.outputDir,
23+
".auth",
24+
"{id}.json"
25+
);
26+
27+
if (fs.existsSync(fileName)) {
28+
// Reuse existing authentication state if any.
29+
await use(fileName);
30+
return;
31+
}
32+
33+
// Important: make sure we authenticate in a clean environment by unsetting storage state.
34+
const page = await browser.newPage({
35+
storageState: undefined,
36+
});
37+
38+
const loginPage = new LoginPage(page);
39+
await loginPage.doLogin();
40+
await page.context().storageState({ path: fileName });
41+
await page.close();
42+
await use(fileName);
43+
},
44+
{ scope: "worker" },
45+
],
46+
47+
loginPage: async ({ page }, use) => {
48+
const loginPage = new LoginPage(page);
49+
await use(loginPage);
50+
},
51+
});

playwright/tests/login.spec.ts

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,14 @@
11
import { test, expect } from "@playwright/test";
2-
3-
test("login through google with API stub", async ({ page, context }) => {
4-
// Mock API key from environment variable
5-
const apiKey = process.env.REFACT_API_KEY ?? "test-api-key";
6-
7-
// Create a mock response that matches GoodPollingResponse type
8-
const mockResponse = {
9-
retcode: "OK",
10-
account: "test@example.com",
11-
inference_url: "https://inference.smallcloud.ai/",
12-
inference: "PRO",
13-
metering_balance: 1000,
14-
questionnaire: true, // TODO: this disables the survey
15-
refact_agent_max_request_num: 100,
16-
refact_agent_request_available: null,
17-
secret_key: apiKey,
18-
tooltip_message: "Welcome to Refact!",
19-
login_message: "You are now logged in",
20-
"longthink-filters": [],
21-
"longthink-functions-today": {},
22-
"longthink-functions-today-v2": {},
23-
};
24-
25-
// Set up route interception before navigating
26-
await context.route(
27-
"https://www.smallcloud.ai/v1/streamlined-login-recall-ticket",
28-
async (route) => {
29-
// Return our mock response
30-
await route.fulfill({
31-
status: 200,
32-
contentType: "application/json",
33-
body: JSON.stringify(mockResponse),
34-
});
35-
}
36-
);
37-
38-
// Navigate to the locally hosted app
39-
await page.goto("http://localhost:5173/");
40-
41-
await expect(
42-
page.getByRole("heading", { name: "Login to Refact.ai" })
43-
).toBeVisible({ timeout: 10000 });
44-
45-
// Wait for the login form to show up when the user is not logged in
46-
await page.waitForSelector('button:has-text("Continue with Google")');
47-
48-
// Click the "Continue with Google" button
49-
await page.click('button:has-text("Continue with Google")');
50-
51-
// Since we're stubbing the API, we don't need to handle the Google popup
52-
// The app should receive our mock response and proceed with login
53-
54-
// Wait for the authentication to complete
55-
await page.waitForLoadState("networkidle");
56-
57-
// Verify we're back at the home page
58-
await expect(page).toHaveURL("http://localhost:5173/");
59-
60-
// Verify that we're logged in (login form should not be visible)
2+
import { LoginPage } from "../fixtures/LoginPage";
3+
4+
test("login through google with API stub", async ({
5+
page,
6+
context,
7+
baseURL,
8+
}) => {
9+
const loginPage = new LoginPage(page);
10+
await loginPage.doLogin(baseURL);
6111
await expect(
6212
page.getByRole("heading", { name: "Login to Refact.ai" })
6313
).not.toBeVisible({ timeout: 10000 });
64-
65-
// Additional verification that the API key was properly set
66-
// This depends on how your app shows the logged-in state
67-
// You might need to adjust this based on your UI
68-
69-
// Example: Check if user menu or profile is visible
70-
// await expect(page.locator('button:has-text("User Profile")')).toBeVisible();
7114
});

playwright/tests/tour.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test, expect } from "../fixtures";
2+
3+
test("Tour", async ({ page, loginPage, baseURL }) => {
4+
page.goto("/");
5+
await expect(page.getByText("Welcome to Refact.ai!")).toBeVisible();
6+
7+
await page.getByRole("button", { name: "Get Started" }).click();
8+
});

refact-agent/engine/tests/emergency_frog_situation/frog.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ def croak(self, n_times):
3333
def swim(self, pond_width, pond_height):
3434
print("Swimming...")
3535
print("Splash! The frog is moving through the water")
36-
self.x += self.vx * DT
37-
self.y += self.vy * DT
36+
self.x += self.vx * DT * 0.8 # Swimming is faster but still slightly slower than jumping
37+
self.y += self.vy * DT * 0.8 # Swimming is faster but still slightly slower than jumping
3838
print("Ripple... ripple...")
3939
self.bounce_off_banks(pond_width, pond_height)
4040
self.x = np.clip(self.x, 0, pond_width)

refact-agent/gui/src/features/UserSurvey/UserSurvey.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const SurveyForm: React.FC<SurveyFormProps> = ({
113113
}, []);
114114

115115
return (
116-
<form onSubmit={onSubmit}>
116+
<form name="refact user survey" onSubmit={onSubmit}>
117117
{questions.map((question) => {
118118
if (isRadioQuestion(question)) {
119119
return (

0 commit comments

Comments
 (0)