(null);
const [replayCounter, setReplayCounter] = useState(0);
- const [serverStatus, setServerStatus] = useState<
- 'connected' | 'pending' | 'failed'
- >('pending');
+ const serverValid = useServerValid();
useEffect(() => {
- let interruptFlag = false;
- Promise.resolve(
- (async () => {
- while (!interruptFlag) {
- const status = await checkServerStatus();
- if (status) {
- setServerStatus('connected');
- } else {
- setServerStatus('failed');
- }
- // sleep 1s
- await new Promise((resolve) => setTimeout(resolve, 1000));
- }
- })(),
- );
-
- return () => {
- interruptFlag = true;
- };
- }, []);
+ if (contextId) {
+ fetch(`${serverBase}/context/${contextId}`)
+ .then((res) => res.json())
+ .then((data) => {
+ const contextObj = JSON.parse(data.context);
+ setUiContext(contextObj);
+ });
+ }
+ }, [contextId]);
const handleRun = useCallback(async () => {
const value = form.getFieldsValue();
@@ -135,8 +120,7 @@ function Playground() {
placeholder = 'What do you want to assert?';
}
- const runButtonDisabled =
- !uiContext || loading || serverStatus !== 'connected';
+ const runButtonDisabled = !uiContext || loading || !serverValid;
// use cmd + enter to run
useEffect(() => {
@@ -180,17 +164,14 @@ function Playground() {
resultDataToShow = {result?.error}
;
}
- const serverTip =
- serverStatus === 'failed' ? (
- <>
- {iconForStatus(serverStatus)} Failed to connect to server. Please launch
- the local server first.
- >
- ) : (
- <>
- {iconForStatus(serverStatus)} {serverStatus}
- >
- );
+ const serverTip = !serverValid ? (
+ <>
+ {iconForStatus('failed')} Failed to connect to server. Please launch the
+ local server first.
+ >
+ ) : (
+ <>{iconForStatus('connected')} Connected to server>
+ );
return (
diff --git a/packages/web-integration/package.json b/packages/web-integration/package.json
index 591d884..eccbca8 100644
--- a/packages/web-integration/package.json
+++ b/packages/web-integration/package.json
@@ -1,129 +1,109 @@
{
- "name": "@midscene/web",
- "description": "An AI-powered automation SDK can control the page, perform assertions, and extract data in JSON format using natural language. See https://midscenejs.com/ for details.",
- "version": "0.6.2",
- "repository": "https://github.com/web-infra-dev/midscene",
- "homepage": "https://midscenejs.com/",
- "jsnext:source": "./src/index.ts",
- "bin": {
- "midscene-playground": "./bin/midscene-playground"
+ "name": "@midscene/web",
+ "description": "An AI-powered automation SDK can control the page, perform assertions, and extract data in JSON format using natural language. See https://midscenejs.com/ for details.",
+ "version": "0.6.2",
+ "repository": "https://github.com/web-infra-dev/midscene",
+ "homepage": "https://midscenejs.com/",
+ "jsnext:source": "./src/index.ts",
+ "bin": {
+ "midscene-playground": "./bin/midscene-playground"
+ },
+ "main": "./dist/lib/index.js",
+ "types": "./dist/types/index.d.ts",
+ "exports": {
+ ".": "./dist/lib/index.js",
+ "./puppeteer": "./dist/lib/puppeteer.js",
+ "./playwright": "./dist/lib/playwright.js",
+ "./playwright-report": "./dist/lib/playwright-report.js",
+ "./playground": "./dist/lib/playground.js",
+ "./debug": "./dist/lib/debug.js",
+ "./constants": "./dist/lib/constants.js",
+ "./html-element": "./dist/lib/html-element/index.js"
+ },
+ "typesVersions": {
+ "*": {
+ ".": ["./dist/types/index.d.ts"],
+ "puppeteer": ["./dist/types/puppeteer.d.ts"],
+ "playwright": ["./dist/types/playwright.d.ts"],
+ "playwright-report": ["./dist/types/playwright-report.d.ts"],
+ "playground": ["./dist/types/playground.d.ts"],
+ "debug": ["./dist/types/debug.d.ts"],
+ "constants": ["./dist/types/constants.d.ts"],
+ "html-element": ["./dist/types/html-element/index.d.ts"]
+ }
+ },
+ "scripts": {
+ "dev": "modern dev",
+ "dev:server": "npm run build && ./bin/midscene-playground",
+ "build": "npm run build:pkg && npm run build:script",
+ "build:pkg": "modern build -c ./modern.config.ts",
+ "build:script": "modern build -c ./modern.inspect.config.ts",
+ "build:watch": "modern build -w -c ./modern.config.ts & modern build -w -c ./modern.inspect.config.ts",
+ "test": "vitest --run",
+ "test:u": "vitest --run -u",
+ "test:ai": "AI_TEST_TYPE=web npm run test",
+ "test:ai:cache": "MIDSCENE_CACHE=true AI_TEST_TYPE=web npm run test",
+ "test:ai:all": "npm run test:ai:web && npm run test:ai:native",
+ "test:ai:native": "MIDSCENE_CACHE=true AI_TEST_TYPE=native npm run test",
+ "new": "modern new",
+ "upgrade": "modern upgrade",
+ "prepublishOnly": "npm run build",
+ "e2e": "playwright test --config=playwright.config.ts",
+ "e2e:report": "MIDSCENE_REPORT=true playwright test --config=playwright.config.ts",
+ "e2e:cache": "MIDSCENE_CACHE=true playwright test --config=playwright.config.ts",
+ "e2e:ui": "playwright test --config=playwright.config.ts --ui",
+ "e2e:ui:cache": "MIDSCENE_CACHE=true playwright test --config=playwright.config.ts --ui"
+ },
+ "files": ["static", "dist", "README.md", "bin"],
+ "dependencies": {
+ "express": "4.21.1",
+ "openai": "4.57.1",
+ "inquirer": "10.1.5",
+ "cors": "2.8.5",
+ "@midscene/core": "workspace:*",
+ "@midscene/shared": "workspace:*",
+ "@xmldom/xmldom": "0.8.10"
+ },
+ "devDependencies": {
+ "@modern-js/module-tools": "2.58.2",
+ "@playwright/test": "1.44.1",
+ "@types/cors": "2.8.12",
+ "@types/fs-extra": "11.0.4",
+ "@types/node": "^18.0.0",
+ "@types/express": "4.17.14",
+ "@wdio/types": "9.0.4",
+ "dotenv": "16.4.5",
+ "fs-extra": "11.2.0",
+ "js-sha256": "0.11.0",
+ "playwright": "1.44.1",
+ "puppeteer": "23.0.2",
+ "typescript": "~5.0.4",
+ "vitest": "^1.6.0",
+ "webdriverio": "9.0.6"
+ },
+ "peerDependencies": {
+ "@playwright/test": "^1.44.1",
+ "playwright": "^1.44.1",
+ "puppeteer": ">=20.0.0",
+ "webdriverio": ">=9.0.6"
+ },
+ "peerDependenciesMeta": {
+ "@playwright/test": {
+ "optional": true
},
- "main": "./dist/lib/index.js",
- "types": "./dist/types/index.d.ts",
- "exports": {
- ".": "./dist/lib/index.js",
- "./puppeteer": "./dist/lib/puppeteer.js",
- "./playwright": "./dist/lib/playwright.js",
- "./playwright-report": "./dist/lib/playwright-report.js",
- "./playground": "./dist/lib/playground.js",
- "./debug": "./dist/lib/debug.js",
- "./constants": "./dist/lib/constants.js",
- "./html-element": "./dist/lib/html-element/index.js"
+ "puppeteer": {
+ "optional": true
},
- "typesVersions": {
- "*": {
- ".": [
- "./dist/types/index.d.ts"
- ],
- "puppeteer": [
- "./dist/types/puppeteer.d.ts"
- ],
- "playwright": [
- "./dist/types/playwright.d.ts"
- ],
- "playwright-report": [
- "./dist/types/playwright-report.d.ts"
- ],
- "playground": [
- "./dist/types/playground.d.ts"
- ],
- "debug": [
- "./dist/types/debug.d.ts"
- ],
- "constants": [
- "./dist/types/constants.d.ts"
- ],
- "html-element": [
- "./dist/types/html-element/index.d.ts"
- ]
- }
- },
- "scripts": {
- "dev": "modern dev",
- "build": "npm run build:pkg && npm run build:script",
- "build:pkg": "modern build -c ./modern.config.ts",
- "build:script": "modern build -c ./modern.inspect.config.ts",
- "build:watch": "modern build -w -c ./modern.config.ts & modern build -w -c ./modern.inspect.config.ts",
- "test": "vitest --run",
- "test:u": "vitest --run -u",
- "test:ai": "AI_TEST_TYPE=web npm run test",
- "test:ai:cache": "MIDSCENE_CACHE=true AI_TEST_TYPE=web npm run test",
- "test:ai:all": "npm run test:ai:web && npm run test:ai:native",
- "test:ai:native": "MIDSCENE_CACHE=true AI_TEST_TYPE=native npm run test",
- "new": "modern new",
- "upgrade": "modern upgrade",
- "prepublishOnly": "npm run build",
- "e2e": "playwright test --config=playwright.config.ts",
- "e2e:report": "MIDSCENE_REPORT=true playwright test --config=playwright.config.ts",
- "e2e:cache": "MIDSCENE_CACHE=true playwright test --config=playwright.config.ts",
- "e2e:ui": "playwright test --config=playwright.config.ts --ui",
- "e2e:ui:cache": "MIDSCENE_CACHE=true playwright test --config=playwright.config.ts --ui"
- },
- "files": [
- "static",
- "dist",
- "README.md",
- "bin"
- ],
- "dependencies": {
- "express": "4.21.1",
- "openai": "4.57.1",
- "inquirer": "10.1.5",
- "cors": "2.8.5",
- "@midscene/core": "workspace:*",
- "@midscene/shared": "workspace:*",
- "@xmldom/xmldom": "0.8.10"
- },
- "devDependencies": {
- "@modern-js/module-tools": "2.58.2",
- "@playwright/test": "1.44.1",
- "@types/cors": "2.8.12",
- "@types/fs-extra": "11.0.4",
- "@types/node": "^18.0.0",
- "@types/express": "4.17.14",
- "@wdio/types": "9.0.4",
- "dotenv": "16.4.5",
- "fs-extra": "11.2.0",
- "js-sha256": "0.11.0",
- "playwright": "1.44.1",
- "puppeteer": "23.0.2",
- "typescript": "~5.0.4",
- "vitest": "^1.6.0",
- "webdriverio": "9.0.6"
- },
- "peerDependencies": {
- "@playwright/test": "^1.44.1",
- "playwright": "^1.44.1",
- "puppeteer": ">=20.0.0",
- "webdriverio": ">=9.0.6"
- },
- "peerDependenciesMeta": {
- "@playwright/test": {
- "optional": true
- },
- "puppeteer": {
- "optional": true
- },
- "webdriverio": {
- "optional": true
- }
- },
- "engines": {
- "node": ">=16.0.0"
- },
- "publishConfig": {
- "access": "public",
- "registry": "https://registry.npmjs.org"
- },
- "license": "MIT"
-}
\ No newline at end of file
+ "webdriverio": {
+ "optional": true
+ }
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "publishConfig": {
+ "access": "public",
+ "registry": "https://registry.npmjs.org"
+ },
+ "license": "MIT"
+}
diff --git a/packages/web-integration/src/playground/server.ts b/packages/web-integration/src/playground/server.ts
index 0552c94..a48940f 100644
--- a/packages/web-integration/src/playground/server.ts
+++ b/packages/web-integration/src/playground/server.ts
@@ -43,25 +43,33 @@ export default class PlaygroundServer {
async launch() {
this.app.use(errorHandler);
- // Serve static files from the staticPath
- this.app.use(express.static(staticPath));
+
+ this.app.use(
+ cors({
+ origin: '*',
+ credentials: true,
+ }),
+ );
+
+ this.app.get('/status', cors(), async (req, res) => {
+ res.send({
+ status: 'ok',
+ });
+ });
// Serve index.html for the root route
this.app.get('/', (req, res) => {
res.sendFile(join(staticPath, 'index.html'));
});
- this.app.get('/playground/status', cors(), async (req, res) => {
- res.send({
- status: 'ok',
- });
+ this.app.get('/playground/:uuid', async (req, res) => {
+ res.sendFile(join(staticPath, 'index.html'));
});
this.app.get('/context/:uuid', async (req, res) => {
const { uuid } = req.params;
const contextFile = this.filePathForUuid(uuid);
assert(existsSync(contextFile), 'Context not found');
-
const context = readFileSync(contextFile, 'utf8');
res.json({
context,
@@ -72,20 +80,21 @@ export default class PlaygroundServer {
// actions from report file
this.app.post(
'/playground-with-context',
- cors(),
- express.urlencoded({ extended: false }),
+ express.json({ limit: '50mb' }),
async (req, res) => {
const context = req.body.context;
assert(context, 'context is required');
const uuid = randomUUID();
this.saveContextFile(uuid, context);
- return res.redirect(`/context/${uuid}`);
+ return res.json({
+ location: `/playground/${uuid}`,
+ uuid,
+ });
},
);
this.app.post(
'/execute',
- cors(),
express.json({ limit: '30mb' }),
async (req, res) => {
const { context, type, prompt } = req.body;
diff --git a/packages/web-integration/tests/unit-test/playground-server.test.ts b/packages/web-integration/tests/unit-test/playground-server.test.ts
index 7095a16..ef8ab2c 100644
--- a/packages/web-integration/tests/unit-test/playground-server.test.ts
+++ b/packages/web-integration/tests/unit-test/playground-server.test.ts
@@ -15,27 +15,25 @@ describe('Playground Server', () => {
});
it('post context', async () => {
- const contextData = JSON.stringify({
- foo: 'bar',
- });
+ const contextValue = 'bar';
const res = await fetch(`${serverBase}/playground-with-context`, {
method: 'POST',
headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Content-Type': 'application/json',
},
- body: `context=${encodeURIComponent(contextData)}`,
- redirect: 'manual',
+ body: JSON.stringify({
+ context: contextValue,
+ }),
});
- expect(res.status).toBe(302);
- const location = res.headers.get('Location');
- expect(location).toBeDefined();
- expect(location).toContain('/context/');
+ expect(res.status).toBe(200);
+ const data = await res.json();
+ const contextId = data.uuid;
// retrieve context
- const contextRes = await fetch(`${serverBase}${location}`);
+ const contextRes = await fetch(`${serverBase}/context/${contextId}`);
const context = await contextRes.json();
expect(context).toBeDefined();
- expect(context.context).toBe(contextData);
+ expect(context.context).toBe(contextValue);
});
});