Files
AutoGPT/autogpt_platform/frontend/src/tests/util.spec.ts
Ubbe d3bfad2a10 refactor(frontend): e2e tests setup + speed + readability (#10388)
## Changes 🏗️

### User creation tests

Now, all tests use the users created via the platform signup in
`global-setup.ts`. Their login details are on a `.auth/user-pool.json`
file. I have the delete the logic that created tests users via Supabase
directly.

### Build tests speed

I have refactored the builder tests, so that, instead of adding 100s of
blocks under a given test user session, a new test user logins and adds
block for each letter:
```
Test user 1
  - logins and adds blocks starting with "a"
Test user 2
  - logins and adds blocks starting with "b"
```
Given that we know the builder becomes slow once we have 30 or more
blocks, in this way a test user never adds more than 10 blocks on a
given test ( _without losing coverage_ ), so we don't need time-outs or
artificially waiting due to the UI being slow.

### Readability test changes

Refactor existing tests, using short-hand utilities, to be:
- easier to write
- clearer to read
- easier to debug

```ts
// Selectors
getId("id") // --> page.getByTestId("id")
getText("foo") // --> page.getByText("id")
getButton("Run") // --> page.getByRole("button", {name: "Run"}
...
// Assetions
const btn = getButton("Save")
isVisible(btn) // --> expect(btn).toBeVisible()
```
These utilities live under `selectors.ts` and `assertions.ts`. Their
usage is optional but encouraged.


## Checklist 📋

### For code changes:
- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
  - [x] Refactored tests code looks good
  - [x] E2E tests are 🟢 on the CI 

### For configuration changes:

No config changes
2025-07-17 10:01:40 +00:00

98 lines
2.7 KiB
TypeScript

import test, { expect } from "@playwright/test";
import { setNestedProperty } from "../lib/utils";
const testCases = [
{
name: "simple property assignment",
path: "name",
value: "John",
expected: { name: "John" },
},
{
name: "nested property with dot notation",
path: "user.settings.theme",
value: "dark",
expected: { user: { settings: { theme: "dark" } } },
},
{
name: "nested property with slash notation",
path: "user/settings/language",
value: "en",
expected: { user: { settings: { language: "en" } } },
},
{
name: "mixed dot and slash notation",
path: "user.settings/preferences.color",
value: "blue",
expected: { user: { settings: { preferences: { color: "blue" } } } },
},
{
name: "overwrite primitive with object",
path: "user.details",
value: { age: 30 },
expected: { user: { details: { age: 30 } } },
},
];
for (const { name, path, value, expected } of testCases) {
test(name, () => {
const obj = {};
setNestedProperty(obj, path, value);
expect(obj).toEqual(expected);
});
}
test("should throw error for null object", () => {
expect(() => {
setNestedProperty(null, "test", "value");
}).toThrow("Target must be a non-null object");
});
test("should throw error for undefined object", () => {
expect(() => {
setNestedProperty(undefined, "test", "value");
}).toThrow("Target must be a non-null object");
});
test("should throw error for non-object target", () => {
expect(() => {
setNestedProperty("string", "test", "value");
}).toThrow("Target must be a non-null object");
});
test("should throw error for empty path", () => {
expect(() => {
setNestedProperty({}, "", "value");
}).toThrow("Path must be a non-empty string");
});
test("should throw error for __proto__ access", () => {
expect(() => {
setNestedProperty({}, "__proto__.malicious", "attack");
}).toThrow("Invalid property name: __proto__");
});
test("should throw error for constructor access", () => {
expect(() => {
setNestedProperty({}, "constructor.prototype.malicious", "attack");
}).toThrow("Invalid property name: constructor");
});
test("should throw error for prototype access", () => {
expect(() => {
setNestedProperty({}, "obj.prototype.malicious", "attack");
}).toThrow("Invalid property name: prototype");
});
test("secure implementation prevents prototype pollution", () => {
const obj = {};
expect(() => {
setNestedProperty(obj, "__proto__.polluted", true);
}).toThrow("Invalid property name: __proto__");
// Verify no pollution occurred
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
expect({}.polluted).toBeUndefined();
});