playwright 1.56.0-beta-1759435110000 → 1.57.0-alpha-2025-10-03
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/agents/generator.md +1 -12
- package/lib/mcp/sdk/http.js +9 -2
- package/lib/mcp/sdk/mdb.js +2 -4
- package/lib/mcp/sdk/server.js +1 -2
- package/lib/mcp/test/testContext.js +13 -0
- package/package.json +2 -2
package/lib/agents/generator.md
CHANGED
|
@@ -46,6 +46,7 @@ application behavior.
|
|
|
46
46
|
- Test title must match the scenario name
|
|
47
47
|
- Includes a comment with the step text before each step execution. Do not duplicate comments if step requires
|
|
48
48
|
multiple actions.
|
|
49
|
+
- Always use best practices from the log when generating tests.
|
|
49
50
|
|
|
50
51
|
<example-generation>
|
|
51
52
|
For following plan:
|
|
@@ -79,18 +80,6 @@ application behavior.
|
|
|
79
80
|
```
|
|
80
81
|
</example-generation>
|
|
81
82
|
|
|
82
|
-
# Best practices
|
|
83
|
-
- Each test has clear, descriptive assertions that validate the expected behavior
|
|
84
|
-
- Includes proper error handling and meaningful failure messages
|
|
85
|
-
- Uses Playwright best practices (page.waitForLoadState, expect.toBeVisible, etc.)
|
|
86
|
-
- Do not improvise, do not add directives that were not asked for
|
|
87
|
-
- Uses reliable locators (preferring data-testid, role-based, or text-based selectors over fragile CSS selectors)
|
|
88
|
-
- Uses local variables for locators that are used multiple times
|
|
89
|
-
- Uses explicit waits rather than arbitrary timeouts
|
|
90
|
-
- Never waits for networkidle or use other discouraged or deprecated apis
|
|
91
|
-
- Is self-contained and can run independently
|
|
92
|
-
- Is deterministic and not prone to flaky behavior
|
|
93
|
-
|
|
94
83
|
<example>
|
|
95
84
|
Context: User wants to test a login flow on their web application.
|
|
96
85
|
user: 'I need a test that logs into my app at localhost:3000 with username admin@test.com and password 123456, then
|
package/lib/mcp/sdk/http.js
CHANGED
|
@@ -67,11 +67,12 @@ function httpAddressToString(address) {
|
|
|
67
67
|
resolvedHost = "localhost";
|
|
68
68
|
return `http://${resolvedHost}:${resolvedPort}`;
|
|
69
69
|
}
|
|
70
|
-
async function installHttpTransport(httpServer, serverBackendFactory, allowedHosts) {
|
|
70
|
+
async function installHttpTransport(httpServer, serverBackendFactory, unguessableUrl, allowedHosts) {
|
|
71
71
|
const url = httpAddressToString(httpServer.address());
|
|
72
72
|
const host = new URL(url).host;
|
|
73
73
|
allowedHosts = (allowedHosts || [host]).map((h) => h.toLowerCase());
|
|
74
74
|
const allowAnyHost = allowedHosts.includes("*");
|
|
75
|
+
const pathPrefix = unguessableUrl ? `/${import_crypto.default.randomUUID()}` : "";
|
|
75
76
|
const sseSessions = /* @__PURE__ */ new Map();
|
|
76
77
|
const streamableSessions = /* @__PURE__ */ new Map();
|
|
77
78
|
httpServer.on("request", async (req, res) => {
|
|
@@ -86,7 +87,12 @@ async function installHttpTransport(httpServer, serverBackendFactory, allowedHos
|
|
|
86
87
|
return res.end("Access is only allowed at " + allowedHosts.join(", "));
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
+
if (!req.url?.startsWith(pathPrefix)) {
|
|
91
|
+
res.statusCode = 404;
|
|
92
|
+
return res.end("Not found");
|
|
93
|
+
}
|
|
94
|
+
const path = req.url?.slice(pathPrefix.length);
|
|
95
|
+
const url2 = new URL(`http://localhost${path}`);
|
|
90
96
|
if (url2.pathname === "/killkillkill" && req.method === "GET") {
|
|
91
97
|
res.statusCode = 200;
|
|
92
98
|
res.end("Killing process");
|
|
@@ -98,6 +104,7 @@ async function installHttpTransport(httpServer, serverBackendFactory, allowedHos
|
|
|
98
104
|
else
|
|
99
105
|
await handleStreamable(serverBackendFactory, req, res, streamableSessions);
|
|
100
106
|
});
|
|
107
|
+
return `${url}${pathPrefix}`;
|
|
101
108
|
}
|
|
102
109
|
async function handleSSE(serverBackendFactory, req, res, url, sessions) {
|
|
103
110
|
if (req.method === "POST") {
|
package/lib/mcp/sdk/mdb.js
CHANGED
|
@@ -153,8 +153,7 @@ async function runOnPauseBackendLoop(backend, introMessage) {
|
|
|
153
153
|
create: () => wrappedBackend
|
|
154
154
|
};
|
|
155
155
|
const httpServer = await mcpHttp.startHttpServer({ port: 0 });
|
|
156
|
-
await mcpHttp.installHttpTransport(httpServer, factory);
|
|
157
|
-
const url = mcpHttp.httpAddressToString(httpServer.address());
|
|
156
|
+
const url = await mcpHttp.installHttpTransport(httpServer, factory, true);
|
|
158
157
|
const client = new mcpBundle.Client({ name: "Pushing client", version: "0.0.0" });
|
|
159
158
|
client.setRequestHandler(mcpBundle.PingRequestSchema, () => ({}));
|
|
160
159
|
const transport = new mcpBundle.StreamableHTTPClientTransport(new URL(process.env.PLAYWRIGHT_DEBUGGER_MCP));
|
|
@@ -175,8 +174,7 @@ async function runOnPauseBackendLoop(backend, introMessage) {
|
|
|
175
174
|
}
|
|
176
175
|
async function startAsHttp(backendFactory, options) {
|
|
177
176
|
const httpServer = await mcpHttp.startHttpServer(options);
|
|
178
|
-
await mcpHttp.installHttpTransport(httpServer, backendFactory);
|
|
179
|
-
return mcpHttp.httpAddressToString(httpServer.address());
|
|
177
|
+
return await mcpHttp.installHttpTransport(httpServer, backendFactory, true);
|
|
180
178
|
}
|
|
181
179
|
class ServerBackendWithCloseListener {
|
|
182
180
|
constructor(backend) {
|
package/lib/mcp/sdk/server.js
CHANGED
|
@@ -138,8 +138,7 @@ async function start(serverBackendFactory, options) {
|
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
140
|
const httpServer = await (0, import_http.startHttpServer)(options);
|
|
141
|
-
const url = (0, import_http.
|
|
142
|
-
await (0, import_http.installHttpTransport)(httpServer, serverBackendFactory, options.allowedHosts);
|
|
141
|
+
const url = await (0, import_http.installHttpTransport)(httpServer, serverBackendFactory, false, options.allowedHosts);
|
|
143
142
|
const mcpConfig = { mcpServers: {} };
|
|
144
143
|
mcpConfig.mcpServers[serverBackendFactory.nameInConfig] = {
|
|
145
144
|
url: `${url}/mcp`
|
|
@@ -65,6 +65,7 @@ class GeneratorJournal {
|
|
|
65
65
|
\`\`\`ts
|
|
66
66
|
${step.code}
|
|
67
67
|
\`\`\``).join("\n\n"));
|
|
68
|
+
result.push(bestPracticesMarkdown);
|
|
68
69
|
return result.join("\n\n");
|
|
69
70
|
}
|
|
70
71
|
}
|
|
@@ -156,6 +157,18 @@ class TestContext {
|
|
|
156
157
|
async close() {
|
|
157
158
|
}
|
|
158
159
|
}
|
|
160
|
+
const bestPracticesMarkdown = `
|
|
161
|
+
# Best practices
|
|
162
|
+
- Do not improvise, do not add directives that were not asked for
|
|
163
|
+
- Use clear, descriptive assertions to validate the expected behavior
|
|
164
|
+
- Use reliable locators from this log
|
|
165
|
+
- Use local variables for locators that are used multiple times
|
|
166
|
+
- Use Playwright waiting assertions and best practices from this log
|
|
167
|
+
- NEVER! use page.waitForLoadState()
|
|
168
|
+
- NEVER! use page.waitForNavigation()
|
|
169
|
+
- NEVER! use page.waitForTimeout()
|
|
170
|
+
- NEVER! use page.evaluate()
|
|
171
|
+
`;
|
|
159
172
|
// Annotate the CommonJS export names for ESM import in node:
|
|
160
173
|
0 && (module.exports = {
|
|
161
174
|
GeneratorJournal,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playwright",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.57.0-alpha-2025-10-03",
|
|
4
4
|
"description": "A high-level API to automate web browsers",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"license": "Apache-2.0",
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"playwright-core": "1.
|
|
67
|
+
"playwright-core": "1.57.0-alpha-2025-10-03"
|
|
68
68
|
},
|
|
69
69
|
"optionalDependencies": {
|
|
70
70
|
"fsevents": "2.3.2"
|