frame.simulator 1.0.0 → 1.0.2

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/batch.ts ADDED
@@ -0,0 +1,82 @@
1
+ import { Command } from './command';
2
+ import { TUserAction } from './types';
3
+
4
+ const PORT: number = parseInt(process.env.PORT || '3010', 10);
5
+
6
+ export class Batch {
7
+ constructor() {
8
+ // Initialize any necessary properties here
9
+ }
10
+
11
+ private async sendRequest(
12
+ command: string,
13
+ data?: TUserAction,
14
+ ): Promise<string> {
15
+ let status = 'blocked';
16
+ try {
17
+ const response = await fetch(`http://localhost:${PORT}/send-command`, {
18
+ method: 'POST',
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ },
22
+ body: JSON.stringify({
23
+ command,
24
+ data,
25
+ }),
26
+ });
27
+ // console.log(`response: ${JSON.stringify(response, null)}`);
28
+ // console.log(`response.status: ${response.status}`);
29
+ if (response.status === 200) {
30
+ status = 'ok';
31
+ }
32
+ return status;
33
+ } catch (error) {
34
+ console.log(`error.status: ${status}`);
35
+ console.error('Error:', error);
36
+ }
37
+ console.log(`return status: ${status}`);
38
+ return status;
39
+ }
40
+
41
+ async selectButton(
42
+ testId: string,
43
+ retries: number = 5,
44
+ delay: number = 1000,
45
+ ): Promise<void> {
46
+ const sleep = (ms: number) =>
47
+ new Promise((resolve) => setTimeout(resolve, ms));
48
+
49
+ for (let attempt = 1; attempt <= retries; attempt++) {
50
+ try {
51
+ if (attempt >= 1) {
52
+ console.log(
53
+ `Attempt ${attempt}/${retries} to click button: ${testId}`,
54
+ );
55
+ }
56
+
57
+ const status = await this.sendRequest(Command.SimulateClick, {
58
+ testId,
59
+ });
60
+
61
+ if (status !== 'ok') {
62
+ console.log('Failed to send button simulation command');
63
+ }
64
+ await sleep(delay);
65
+ return; // Success, exit the retry loop
66
+ } catch (error) {
67
+ console.error('Error in main:', error);
68
+ }
69
+ }
70
+ }
71
+
72
+ async sampleClickCanvasDrawAt(x: number, y: number) {
73
+ console.log(`sampleClickCanvasDrawAt(${x}, ${y})`);
74
+ await this.sendRequest(Command.SimulateClickOnCanvas, {
75
+ testId: 'canvas.draw',
76
+ x,
77
+ y,
78
+ });
79
+ // Small delay to ensure element is fully ready
80
+ await new Promise((resolve) => setTimeout(resolve, 300));
81
+ }
82
+ }
package/command-server.ts CHANGED
@@ -32,7 +32,7 @@ interface HealthResponse {
32
32
  }
33
33
 
34
34
  const app: express.Application = express();
35
- const PORT: number = 3010;
35
+ const PORT: number = parseInt(process.env.PORT || '3010', 10);
36
36
 
37
37
  // Middleware
38
38
  app.use(cors());
package/command.ts ADDED
@@ -0,0 +1,6 @@
1
+ export enum Command {
2
+ SimulateClick = 'SimulateClick',
3
+ SimulateClickOnCanvas = 'SimulateClickOnCanvas',
4
+ SimulateInput = 'SimulateInput',
5
+ SimulateCheck = 'SimulateUserCheck',
6
+ }
@@ -0,0 +1,30 @@
1
+ import { Command } from './command';
2
+ import { Simulator } from './simulator';
3
+ import { TUserAction, TClick, TClickOnCanvas, TInput } from './types';
4
+
5
+ export function useCommandHandler() {
6
+ const handleCommand = async (command: string, data: TUserAction) => {
7
+ const simulator = new Simulator();
8
+
9
+ switch (command) {
10
+ case Command.SimulateClick:
11
+ return simulator.simulateUserClick(data as TClick);
12
+ case Command.SimulateClickOnCanvas:
13
+ return simulator.simulateClickOnCanvas(data as TClickOnCanvas);
14
+ // case Command.MainScaleFrame:
15
+ // return simulator.simulateScaleFrame(data as TScaleFrame);
16
+ case Command.SimulateInput:
17
+ return simulator.simulateUserInput(data as TInput);
18
+ case Command.SimulateCheck:
19
+ return simulator.simulateUserCheck(data as TClick);
20
+ default:
21
+ console.warn('Unknown command:', command);
22
+ console.log(`SimulateUserAction command received with data:`, data);
23
+ throw new Error(
24
+ 'SimulateUserAction command should be handled by simulateUserAction function directly',
25
+ );
26
+ }
27
+ };
28
+
29
+ return { handleCommand };
30
+ }
package/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { Simulator } from './simulator';
2
+ export { TClick, TClickOnCanvas, TScaleFrame, TUserAction } from './types';
3
+ export { Command } from './command';
4
+ export { useCommandHandler } from './commandHandler';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frame.simulator",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A simulator for testing form interactions in a controlled environment.",
5
5
  "main": "index.js",
6
6
  "license": "MIT",
@@ -12,6 +12,9 @@
12
12
  "frame.constants": "^1.0.5"
13
13
  },
14
14
  "devDependencies": {
15
+ "@types/cors": "^2.8.19",
16
+ "@types/express": "^5.0.6",
17
+ "@types/node": "^25.3.0",
15
18
  "cors": "^2.8.5",
16
19
  "express": "^5.2.1",
17
20
  "frame.constants": "^1.0.5",
package/simulator.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { green, red, reset } from 'frame.constants';
2
- import { TClick, TClickOnCanvas, TScaleFrame } from './types';
2
+ import { TClick, TClickOnCanvas, TInput } from './types';
3
3
 
4
4
  export class Simulator {
5
5
  constructor() {
@@ -77,7 +77,8 @@ export class Simulator {
77
77
  }
78
78
  }
79
79
 
80
- simulateUserInput(testId: string, value: string) {
80
+ simulateUserInput(data: TInput) {
81
+ const { testId, value } = data;
81
82
  const element = this.findHTMLElement(testId, HTMLDivElement, 'input');
82
83
 
83
84
  if (element) {
@@ -95,15 +96,15 @@ export class Simulator {
95
96
  }
96
97
  }
97
98
 
98
- simulateScaleFrame(scaleValues: TScaleFrame) {
99
- const { length, height } = scaleValues;
100
- console.log(
101
- `${red}Simulating scale frame with length: ${length}, height: ${height}${reset}`,
102
- );
103
- this.simulateUserInput('ScaleInput.input.length', length.toString());
104
- this.simulateUserInput('ScaleInput.input.height', height.toString());
105
- this.simulateUserCheck({ testId: 'ShowOptions.cbx.scaledBox' });
106
- this.simulateUserClick({ testId: 'ScaleForm.button.apply' });
107
- this.simulateUserCheck({ testId: 'ShowOptions.cbx.points' });
108
- }
99
+ // simulateScaleFrame(scaleValues: TScaleFrame) {
100
+ // const { length, height } = scaleValues;
101
+ // console.log(
102
+ // `${red}Simulating scale frame with length: ${length}, height: ${height}${reset}`,
103
+ // );
104
+ // this.simulateUserInput('ScaleInput.input.length', length.toString());
105
+ // this.simulateUserInput('ScaleInput.input.height', height.toString());
106
+ // this.simulateUserCheck({ testId: 'ShowOptions.cbx.scaledBox' });
107
+ // this.simulateUserClick({ testId: 'ScaleForm.button.apply' });
108
+ // this.simulateUserCheck({ testId: 'ShowOptions.cbx.points' });
109
+ // }
109
110
  }
package/types.ts CHANGED
@@ -2,6 +2,11 @@ export type TClick = {
2
2
  testId: string;
3
3
  };
4
4
 
5
+ export type TInput = {
6
+ testId: string;
7
+ value: string;
8
+ };
9
+
5
10
  export type TClickOnCanvas = {
6
11
  x: number;
7
12
  y: number;
@@ -12,4 +17,4 @@ export type TScaleFrame = {
12
17
  height: number;
13
18
  };
14
19
 
15
- export type TUserAction = TClickOnCanvas | TScaleFrame | TClick;
20
+ export type TUserAction = TClickOnCanvas | TScaleFrame | TClick | TInput;
package/command-server.js DELETED
@@ -1,132 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
- function verb(n) { return function (v) { return step([n, v]); }; }
15
- function step(op) {
16
- if (f) throw new TypeError("Generator is already executing.");
17
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
- if (y = 0, t) op = [op[0] & 2, t.value];
20
- switch (op[0]) {
21
- case 0: case 1: t = op; break;
22
- case 4: _.label++; return { value: op[1], done: false };
23
- case 5: _.label++; y = op[1]; op = [0]; continue;
24
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
- default:
26
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
- if (t[2]) _.ops.pop();
31
- _.trys.pop(); continue;
32
- }
33
- op = body.call(thisArg, _);
34
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
- }
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- var express_1 = require("express");
40
- var cors_1 = require("cors");
41
- var app = (0, express_1.default)();
42
- var PORT = 3010;
43
- // Middleware
44
- app.use((0, cors_1.default)());
45
- app.use(express_1.default.json());
46
- // Store for command queue and results
47
- var commandQueue = [];
48
- var commandResults = new Map();
49
- // Endpoint to receive commands from batch processor
50
- app.post('/send-command', function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
51
- var _a, command, data, commandId, attempts, maxAttempts, result, error_1;
52
- return __generator(this, function (_b) {
53
- switch (_b.label) {
54
- case 0:
55
- _b.trys.push([0, 4, , 5]);
56
- _a = req.body, command = _a.command, data = _a.data;
57
- console.log('Received command:', command, data);
58
- commandId = Date.now().toString();
59
- commandQueue.push({
60
- id: commandId,
61
- command: command,
62
- data: data,
63
- timestamp: new Date(),
64
- });
65
- attempts = 0;
66
- maxAttempts = 50;
67
- _b.label = 1;
68
- case 1:
69
- if (!(attempts < maxAttempts)) return [3 /*break*/, 3];
70
- if (commandResults.has(commandId)) {
71
- result = commandResults.get(commandId);
72
- commandResults.delete(commandId);
73
- return [2 /*return*/, res.json(result)];
74
- }
75
- return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 100); })];
76
- case 2:
77
- _b.sent();
78
- attempts++;
79
- return [3 /*break*/, 1];
80
- case 3:
81
- // Timeout
82
- res.status(408).json({
83
- status: 'error',
84
- message: 'Command timeout',
85
- });
86
- return [3 /*break*/, 5];
87
- case 4:
88
- error_1 = _b.sent();
89
- console.error('Server error:', error_1);
90
- res.status(500).json({
91
- status: 'error',
92
- message: error_1 instanceof Error ? error_1.message : 'Unknown error',
93
- });
94
- return [3 /*break*/, 5];
95
- case 5: return [2 /*return*/];
96
- }
97
- });
98
- }); });
99
- // Endpoint for React app to poll for commands
100
- app.get('/poll-commands', function (req, res) {
101
- if (commandQueue.length > 0) {
102
- var command = commandQueue.shift();
103
- res.json(command || null);
104
- }
105
- else {
106
- res.json(null);
107
- }
108
- });
109
- // Endpoint for React app to send command results
110
- app.post('/command-result', function (req, res) {
111
- var _a = req.body, commandId = _a.commandId, result = _a.result;
112
- commandResults.set(commandId, result);
113
- res.json({ status: 'ok' });
114
- });
115
- // Health check
116
- app.get('/health', function (req, res) {
117
- res.json({
118
- status: 'healthy',
119
- queueLength: commandQueue.length,
120
- timestamp: new Date(),
121
- });
122
- });
123
- app.listen(PORT, function () {
124
- console.log('COMMAND SERVER (TYPESCRIPT VERSION)');
125
- console.log("Command server running on http://localhost:".concat(PORT));
126
- console.log('Endpoints:');
127
- console.log(' POST /send-command - Receive batch commands');
128
- console.log(' GET /poll-commands - React app polls for commands');
129
- console.log(' POST /command-result - React app sends results');
130
- console.log(' GET /health - Server health check');
131
- });
132
- exports.default = app;
@@ -1,3 +0,0 @@
1
- import express from 'express';
2
- declare const app: express.Application;
3
- export default app;
@@ -1,89 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const express_1 = __importDefault(require("express"));
7
- const cors_1 = __importDefault(require("cors"));
8
- const app = (0, express_1.default)();
9
- const PORT = 3010;
10
- // Middleware
11
- app.use((0, cors_1.default)());
12
- app.use(express_1.default.json());
13
- // Store for command queue and results
14
- let commandQueue = [];
15
- let commandResults = new Map();
16
- // Endpoint to receive commands from batch processor
17
- app.post('/send-command', async (req, res) => {
18
- try {
19
- const { command, data } = req.body;
20
- console.log('Received command:', command, data);
21
- // For browser-based commands, we'll use a different approach
22
- // Store the command and let the React app poll for it
23
- const commandId = Date.now().toString();
24
- commandQueue.push({
25
- id: commandId,
26
- command,
27
- data,
28
- timestamp: new Date(),
29
- });
30
- // Wait for result (with timeout)
31
- let attempts = 0;
32
- const maxAttempts = 50; // 5 seconds timeout
33
- while (attempts < maxAttempts) {
34
- if (commandResults.has(commandId)) {
35
- const result = commandResults.get(commandId);
36
- commandResults.delete(commandId);
37
- return res.json(result);
38
- }
39
- await new Promise((resolve) => setTimeout(resolve, 100));
40
- attempts++;
41
- }
42
- // Timeout
43
- res.status(408).json({
44
- status: 'error',
45
- message: 'Command timeout',
46
- });
47
- }
48
- catch (error) {
49
- console.error('Server error:', error);
50
- res.status(500).json({
51
- status: 'error',
52
- message: error instanceof Error ? error.message : 'Unknown error',
53
- });
54
- }
55
- });
56
- // Endpoint for React app to poll for commands
57
- app.get('/poll-commands', (req, res) => {
58
- if (commandQueue.length > 0) {
59
- const command = commandQueue.shift();
60
- res.json(command || null);
61
- }
62
- else {
63
- res.json(null);
64
- }
65
- });
66
- // Endpoint for React app to send command results
67
- app.post('/command-result', (req, res) => {
68
- const { commandId, result } = req.body;
69
- commandResults.set(commandId, result);
70
- res.json({ status: 'ok' });
71
- });
72
- // Health check
73
- app.get('/health', (req, res) => {
74
- res.json({
75
- status: 'healthy',
76
- queueLength: commandQueue.length,
77
- timestamp: new Date(),
78
- });
79
- });
80
- app.listen(PORT, () => {
81
- console.log('COMMAND SERVER (TYPESCRIPT VERSION)');
82
- console.log(`Command server running on http://localhost:${PORT}`);
83
- console.log('Endpoints:');
84
- console.log(' POST /send-command - Receive batch commands');
85
- console.log(' GET /poll-commands - React app polls for commands');
86
- console.log(' POST /command-result - React app sends results');
87
- console.log(' GET /health - Server health check');
88
- });
89
- exports.default = app;
@@ -1,12 +0,0 @@
1
- import { TClick, TClickOnCanvas, TScaleFrame } from './types';
2
- export declare class Simulator {
3
- constructor();
4
- findHTMLElement(testId: string, elementType: typeof HTMLElement, type?: string): HTMLElement | null;
5
- simulateClickOnCanvas(data: TClickOnCanvas): void;
6
- simulateUserClick(data: TClick): void;
7
- simulateUserCheck(data: TClick): void;
8
- simulateUserInput(testId: string, value: string): {
9
- status: string;
10
- } | undefined;
11
- simulateScaleFrame(scaleValues: TScaleFrame): void;
12
- }
package/dist/simulator.js DELETED
@@ -1,93 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Simulator = void 0;
4
- const frame_constants_1 = require("frame.constants");
5
- class Simulator {
6
- constructor() {
7
- console.log('Simulator initialized');
8
- }
9
- findHTMLElement(testId, elementType, type) {
10
- if (type) {
11
- console.log(`${frame_constants_1.green}Simulating ${type} on element with testId: ${testId}${frame_constants_1.reset}`);
12
- }
13
- const element = document.querySelector(`[data-testid="${testId}"]`);
14
- if (element) {
15
- if (element instanceof elementType) {
16
- }
17
- else {
18
- console.error(`Element found but not a ${elementType.name} for ${type} simulation: ${testId}`);
19
- }
20
- }
21
- else {
22
- console.error(`Element not found for ${type} simulation: ${testId}`);
23
- }
24
- return element;
25
- }
26
- simulateClickOnCanvas(data) {
27
- const { x, y } = data;
28
- const canvas = this.findHTMLElement('canvas.draw', HTMLCanvasElement, 'click');
29
- if (canvas) {
30
- const rect = canvas.getBoundingClientRect();
31
- const event = new MouseEvent('click', {
32
- clientX: rect.left + rect.width / 2 + x, // Convert canvas-relative to screen coordinates
33
- clientY: rect.top + rect.height / 2 - y, // Convert canvas-relative to screen coordinates (flip Y)
34
- bubbles: true,
35
- });
36
- // Set batch properties
37
- // @ts-ignore - Add custom properties for batch identification
38
- event.isBatch = true;
39
- // @ts-ignore - Store original canvas-relative coordinates
40
- event.batchX = x;
41
- // @ts-ignore - Store original canvas-relative coordinates
42
- event.batchY = y;
43
- canvas.dispatchEvent(event);
44
- }
45
- }
46
- simulateUserClick(data) {
47
- const { testId } = data;
48
- const element = this.findHTMLElement(testId, HTMLButtonElement, 'click');
49
- if (element) {
50
- const event = new MouseEvent('click', { bubbles: true });
51
- // @ts-ignore - Add custom property to identify this as a batch click
52
- event.isBatch = true;
53
- element.click();
54
- }
55
- }
56
- simulateUserCheck(data) {
57
- const { testId } = data;
58
- const element = this.findHTMLElement(testId, HTMLInputElement, 'check');
59
- if (element) {
60
- const event = new MouseEvent('click', { bubbles: true });
61
- // @ts-ignore - Add custom property to identify this as a batch click
62
- event.isBatch = true;
63
- element.dispatchEvent(event);
64
- }
65
- }
66
- simulateUserInput(testId, value) {
67
- const element = this.findHTMLElement(testId, HTMLDivElement, 'input');
68
- if (element) {
69
- if (element instanceof HTMLInputElement) {
70
- element.value = value.toString();
71
- element.dispatchEvent(new Event('input', { bubbles: true }));
72
- return { status: 'ok' };
73
- }
74
- else if (element instanceof HTMLDivElement) {
75
- const childElement = element.firstChild;
76
- if (childElement instanceof HTMLInputElement) {
77
- childElement.value = value || '';
78
- childElement.dispatchEvent(new Event('input', { bubbles: true }));
79
- }
80
- }
81
- }
82
- }
83
- simulateScaleFrame(scaleValues) {
84
- const { length, height } = scaleValues;
85
- console.log(`${frame_constants_1.red}Simulating scale frame with length: ${length}, height: ${height}${frame_constants_1.reset}`);
86
- this.simulateUserInput('ScaleInput.input.length', length.toString());
87
- this.simulateUserInput('ScaleInput.input.height', height.toString());
88
- this.simulateUserCheck({ testId: 'ShowOptions.cbx.scaledBox' });
89
- this.simulateUserClick({ testId: 'ScaleForm.button.apply' });
90
- this.simulateUserCheck({ testId: 'ShowOptions.cbx.points' });
91
- }
92
- }
93
- exports.Simulator = Simulator;
@@ -1 +0,0 @@
1
- {"root":["../command-server.ts","../simulator.ts","../types.ts"],"errors":true,"version":"5.6.3"}
package/dist/types.d.ts DELETED
@@ -1,12 +0,0 @@
1
- export type TClick = {
2
- testId: string;
3
- };
4
- export type TClickOnCanvas = {
5
- x: number;
6
- y: number;
7
- };
8
- export type TScaleFrame = {
9
- length: number;
10
- height: number;
11
- };
12
- export type TUserAction = TClickOnCanvas | TScaleFrame | TClick;
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });