@q-agent/agent 0.1.1 → 0.1.6

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.
@@ -135,6 +135,25 @@ function mockFetch(handler) {
135
135
  const body = JSON.parse(calls[0].init.body);
136
136
  strict_1.default.deepEqual(body, { passed: 3, failed: 1, log: "tail" });
137
137
  });
138
+ (0, node_test_1.test)("postHealFix posts the attempt to /agent/heal/{caseId}/fix and returns the action", async () => {
139
+ mockFetch(() => Response.json({ action: "fixed", code: "// fixed", diff: "@@" }));
140
+ const out = await api.postHealFix(cfg, 99, {
141
+ currentCode: "// old", error: "boom", output: "tail", domDistilled: { path: "/x" }, attempt: 2,
142
+ });
143
+ strict_1.default.equal(calls[0].url, "http://127.0.0.1:8787/agent/heal/99/fix");
144
+ strict_1.default.equal(calls[0].init.method, "POST");
145
+ const body = JSON.parse(calls[0].init.body);
146
+ strict_1.default.deepEqual(body, { currentCode: "// old", error: "boom", output: "tail", domDistilled: { path: "/x" }, attempt: 2 });
147
+ strict_1.default.equal(out.action, "fixed");
148
+ strict_1.default.equal(out.code, "// fixed");
149
+ });
150
+ (0, node_test_1.test)("postHealFinalize posts the outcome to /agent/heal/{caseId}/finalize", async () => {
151
+ mockFetch(() => new Response(null, { status: 200 }));
152
+ await api.postHealFinalize(cfg, 99, { finalStatus: "pass", finalCode: "// x", attempts: [] });
153
+ strict_1.default.equal(calls[0].url, "http://127.0.0.1:8787/agent/heal/99/finalize");
154
+ const body = JSON.parse(calls[0].init.body);
155
+ strict_1.default.equal(body.finalStatus, "pass");
156
+ });
138
157
  (0, node_test_1.test)("redeemDevice posts code+name with no auth header", async () => {
139
158
  mockFetch(() => Response.json({ deviceToken: "abc", deviceId: 7 }));
140
159
  const result = await api.redeemDevice("http://127.0.0.1:8787", "PAIR123", "my-laptop");
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for the injected-fixtures port (`src/playwrightConfig.ts`).
4
+ * Mirrors the server's `test_fixtures_ts_contents` / `test_apply_fixtures_always_injects`
5
+ * (api/tests/test_execution.py) so the agent's DOM capture stays in lock-step
6
+ * with the server runner.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __importDefault = (this && this.__importDefault) || function (mod) {
42
+ return (mod && mod.__esModule) ? mod : { "default": mod };
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ const strict_1 = __importDefault(require("node:assert/strict"));
46
+ const fs = __importStar(require("node:fs"));
47
+ const os = __importStar(require("node:os"));
48
+ const path = __importStar(require("node:path"));
49
+ const node_test_1 = require("node:test");
50
+ const playwrightConfig_1 = require("../src/playwrightConfig");
51
+ (0, node_test_1.test)("fixturesTs always wires DOM capture; sessionStorage replay is gated", () => {
52
+ const sessionFile = "/tmp/sessionStorage.json";
53
+ const replay = (0, playwrightConfig_1.fixturesTs)(sessionFile, true);
54
+ strict_1.default.ok(replay.includes("export const test"));
55
+ strict_1.default.ok(replay.includes("testInfo.attach('qagent-dom-raw'"));
56
+ strict_1.default.ok(replay.includes("testInfo.attach('qagent-dom-distilled'"));
57
+ strict_1.default.ok(replay.includes(JSON.stringify(sessionFile)));
58
+ strict_1.default.ok(replay.includes("addInitScript"), "replay=true injects the session init script");
59
+ const noReplay = (0, playwrightConfig_1.fixturesTs)(sessionFile, false);
60
+ strict_1.default.ok(noReplay.includes("testInfo.attach('qagent-dom-distilled'"));
61
+ strict_1.default.ok(!noReplay.includes("addInitScript"), "replay=false drops the session init script");
62
+ });
63
+ (0, node_test_1.test)("applyFixtures always rewrites imports to './fixtures' + writes fixtures.ts", () => {
64
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "qa-fx-"));
65
+ const specName = "1428-TC-01.spec.ts";
66
+ const specPath = path.join(dir, specName);
67
+ const original = "import { test, expect } from '@playwright/test';\n" +
68
+ "test('x', async ({ page }) => { await page.goto('/'); });\n";
69
+ fs.writeFileSync(specPath, original, "utf-8");
70
+ const sessionFile = path.join(dir, "sessionStorage.json");
71
+ // Even without session replay, DOM capture means fixtures are injected.
72
+ (0, playwrightConfig_1.applyFixtures)(dir, [specName], sessionFile, false);
73
+ const rewritten = fs.readFileSync(specPath, "utf-8");
74
+ strict_1.default.ok(rewritten.includes("'./fixtures'"));
75
+ strict_1.default.ok(!rewritten.includes("'@playwright/test'"));
76
+ const fixtures = fs.readFileSync(path.join(dir, "fixtures.ts"), "utf-8");
77
+ strict_1.default.ok(fixtures.includes("qagent-dom-distilled"));
78
+ strict_1.default.ok(!fixtures.includes("addInitScript"));
79
+ // With replay enabled, the init script is added; specs stay pointed at './fixtures'.
80
+ (0, playwrightConfig_1.applyFixtures)(dir, [specName], sessionFile, true);
81
+ strict_1.default.ok(fs.readFileSync(specPath, "utf-8").includes("'./fixtures'"));
82
+ strict_1.default.ok(fs.readFileSync(path.join(dir, "fixtures.ts"), "utf-8").includes("addInitScript"));
83
+ fs.rmSync(dir, { recursive: true, force: true });
84
+ });
@@ -139,6 +139,8 @@ const report_1 = require("../src/report");
139
139
  { name: "screenshot", path: "/tmp/shot.png" },
140
140
  { name: "video", path: "/tmp/vid.webm" },
141
141
  { name: "trace", path: "/tmp/trace.zip" },
142
+ { name: "qagent-dom-raw", path: "/tmp/dom.html" },
143
+ { name: "qagent-dom-distilled", path: "/tmp/dom.json" },
142
144
  { name: "stdout", path: "/tmp/stdout.txt" },
143
145
  { name: "screenshot", path: "" },
144
146
  ],
@@ -155,6 +157,8 @@ const report_1 = require("../src/report");
155
157
  { kind: "screenshot", path: "/tmp/shot.png" },
156
158
  { kind: "video", path: "/tmp/vid.webm" },
157
159
  { kind: "trace", path: "/tmp/trace.zip" },
160
+ { kind: "dom", path: "/tmp/dom.html" },
161
+ { kind: "dom-distilled", path: "/tmp/dom.json" },
158
162
  ]);
159
163
  });
160
164
  (0, node_test_1.test)("flattens nested describe-block suites under one file", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q-agent/agent",
3
- "version": "0.1.1",
3
+ "version": "0.1.6",
4
4
  "description": "Q-Agent Local Agent — claims execution jobs from the Q-Agent server and runs Playwright locally, so manual login/MFA happens on the user's own machine and session credentials never leave it.",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -27,17 +27,51 @@
27
27
  "test": "npm run build && node --test dist/test",
28
28
  "release": "node scripts/release.mjs",
29
29
  "prepublishOnly": "npm run build",
30
- "package:win": "node scripts/package-win.mjs"
30
+ "package:win": "node scripts/package-win.mjs",
31
+ "desktop": "npm run build && electron electron/main.cjs",
32
+ "dist:desktop": "npm run build && electron-builder --win"
31
33
  },
32
34
  "dependencies": {
33
35
  "@playwright/test": "^1.61.1",
34
36
  "commander": "^12.1.0",
37
+ "electron-updater": "^6.3.9",
35
38
  "playwright": "^1.61.1"
36
39
  },
37
40
  "devDependencies": {
38
41
  "@types/node": "^20.14.0",
42
+ "electron": "^33.2.0",
43
+ "electron-builder": "^25.1.8",
39
44
  "esbuild": "^0.24.0",
40
45
  "postject": "^1.0.0-alpha.6",
41
46
  "typescript": "^5.5.4"
47
+ },
48
+ "build": {
49
+ "appId": "click.chuongnd.qagent-agent",
50
+ "productName": "Q-Agent Local Agent",
51
+ "extraMetadata": {
52
+ "main": "electron/main.cjs",
53
+ "qagentServer": "https://qagent.chuongnd.click/api"
54
+ },
55
+ "files": [
56
+ "dist/**/*",
57
+ "electron/**/*",
58
+ "vendor/**/*",
59
+ "package.json"
60
+ ],
61
+ "artifactName": "qagent-agent-setup.${ext}",
62
+ "asar": false,
63
+ "win": {
64
+ "target": "nsis",
65
+ "signAndEditExecutable": false
66
+ },
67
+ "publish": [
68
+ {
69
+ "provider": "generic",
70
+ "url": "https://qagent.chuongnd.click/downloads/"
71
+ }
72
+ ],
73
+ "directories": {
74
+ "output": "dist-bin/desktop"
75
+ }
42
76
  }
43
77
  }