demo done
This commit is contained in:
250
mainpage.po.ts
250
mainpage.po.ts
@@ -1,231 +1,47 @@
|
||||
import { Util } from "../util";
|
||||
|
||||
export class Mainpage {
|
||||
static button = ".mdc-button"
|
||||
static menubutton = ".mat-mdc-menu-item"
|
||||
static menutextbutton = ".mat-mdc-menu-item-text"
|
||||
static openmenu = ".mat-mdc-menu-trigger"
|
||||
static navbuttons = ".mat-mdc-tooltip-trigger"
|
||||
static inputfield = ".mat-mdc-input-element"
|
||||
static panelbutton = ".cmdsk-wlcm__panel-action" //cmdsk-wlcm__panel-action
|
||||
static yuvform = ".yuv-object-form-element"
|
||||
static autocomplete = ".mat-mdc-autocomplete-panel"
|
||||
static calender = ".calender"
|
||||
static checkbox = ".mdc-checkbox"
|
||||
static formcategory = ".main"
|
||||
static buttontext = ".mdc-button__label"
|
||||
static tab = ".mdc-tab"
|
||||
static casefunction = ".mdc-evolution-chip__action"
|
||||
static documentmenubutton = ".cdk-menu-item"
|
||||
static searchfield = ".search"
|
||||
static loadingspinner = ".mat-mdc-progress-spinner"
|
||||
static listitem = ".mdc-list-item"
|
||||
static tile = ".tile"
|
||||
static button = ".dummy"
|
||||
static matmdctooltiptriggerclass = ".mat-mdc-tooltip-trigger"
|
||||
static matbuttontogglebuttonclass = ".mat-button-toggle-button"
|
||||
static matmdcinputelementclass = ".mat-mdc-input-element"
|
||||
static startsearcharia = "[aria-label='Start search']"
|
||||
|
||||
static treenode = ".mat-tree-node"
|
||||
|
||||
get Uploadbutton() {
|
||||
return cy.nccontains(Mainpage.menubutton, 'Upload document');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
get startsearchsearch() {
|
||||
return cy.nccontains(Mainpage.startsearcharia, 'search');
|
||||
}
|
||||
|
||||
get Casecreatebutton() {
|
||||
return cy.nccontains(Mainpage.menubutton, ' Create case ');
|
||||
get matmdcinputelement() {
|
||||
return cy.get(Mainpage.matmdcinputelementclass);
|
||||
}
|
||||
|
||||
get Openbutton() {
|
||||
return cy.nccontains(Mainpage.openmenu, "add");
|
||||
get matmdctooltiptriggercloud_circle() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'cloud_circle');
|
||||
}
|
||||
|
||||
get Navbuttons() {
|
||||
return cy.get(Mainpage.navbuttons);
|
||||
get matmdctooltiptriggerlibrary_books() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'library_books');
|
||||
}
|
||||
|
||||
get Homebutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, 'home')
|
||||
get matmdctooltiptriggermove_to_inbox() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'move_to_inbox');
|
||||
}
|
||||
|
||||
get Casenavbutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, 'cases')
|
||||
get matbuttontogglebuttondark() {
|
||||
return cy.nccontains(Mainpage.matbuttontogglebuttonclass, 'Dark');
|
||||
}
|
||||
|
||||
get Dokumentenavbutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, 'description')
|
||||
get matbuttontogglebuttonsystem() {
|
||||
return cy.nccontains(Mainpage.matbuttontogglebuttonclass, 'System');
|
||||
}
|
||||
|
||||
get Deletebutton(){
|
||||
return cy.nccontains(Mainpage.documentmenubutton, 'delete')
|
||||
}
|
||||
|
||||
Casedeletionbutton(selector: string){
|
||||
return cy.contains(selector).parent().parent().parent().find(Mainpage.navbuttons).eq(0)
|
||||
}
|
||||
|
||||
|
||||
get Kebabbutton(){
|
||||
return cy.ncnccontains(Mainpage.openmenu, 'more_vert')
|
||||
}
|
||||
|
||||
get Deleteworkspacebutton(){
|
||||
return cy.nccontains(Mainpage.menubutton, 'Delete workspace')
|
||||
}
|
||||
|
||||
get Confirmbutton(){
|
||||
return cy.nccontains(Mainpage.button, 'Confirm')
|
||||
}
|
||||
|
||||
get Deleteconfirmbutton(){
|
||||
return cy.nccontains(Mainpage.button, 'Delete')
|
||||
}
|
||||
|
||||
get Inputfield() {
|
||||
return cy.get(Mainpage.inputfield);
|
||||
}
|
||||
|
||||
get Panelbutton() {
|
||||
return cy.get(Mainpage.panelbutton);
|
||||
}
|
||||
|
||||
get CasePanelbutton() {
|
||||
return cy.nccontains(Mainpage.panelbutton, 'case')
|
||||
}
|
||||
|
||||
get Yuvform(){
|
||||
return cy.get(Mainpage.yuvform)
|
||||
}
|
||||
|
||||
Caseform(selector: string){
|
||||
return cy.nccontains(Mainpage.yuvform, selector)
|
||||
}
|
||||
|
||||
get Autocomplete(){
|
||||
return cy.get(Mainpage.autocomplete)
|
||||
}
|
||||
|
||||
Caseformcalender(selector: string){
|
||||
return cy.nccontains(Mainpage.yuvform, selector).find(Mainpage.calender)
|
||||
}
|
||||
|
||||
get Formdateselect(){
|
||||
return cy.nccontains('button', "Select")
|
||||
}
|
||||
|
||||
get Checkbox(){
|
||||
return cy.get(Mainpage.checkbox)
|
||||
}
|
||||
|
||||
|
||||
Formcategory(selector: string){
|
||||
return cy.nccontains(Mainpage.formcategory, selector)
|
||||
}
|
||||
|
||||
get Formconfirm(){
|
||||
return cy.nccontains('button', /^ Create $/i)
|
||||
}
|
||||
|
||||
get Historytab(){
|
||||
return cy.nccontains(Mainpage.tab, "history")
|
||||
}
|
||||
|
||||
get Metadatatab(){
|
||||
return cy.nccontains(Mainpage.tab, "Metadata")
|
||||
}
|
||||
|
||||
get Renamebutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, "Rename")
|
||||
}
|
||||
|
||||
get Renamefield(){
|
||||
return cy.get('yuv-string[formcontrolname="name"] input')
|
||||
}
|
||||
|
||||
get Renameconfirm(){
|
||||
return cy.nccontains(Mainpage.button, "Rename")
|
||||
}
|
||||
|
||||
|
||||
CheckAIfunction(wantedfunction: string){
|
||||
return cy.nccontains(Mainpage.casefunction, wantedfunction)
|
||||
}
|
||||
|
||||
CheckAIlogo(){
|
||||
return cy.nccontains("robot_2")
|
||||
}
|
||||
|
||||
get sortingbutton(){
|
||||
return cy.nccontains("swap_vert")
|
||||
}
|
||||
|
||||
|
||||
get firsttreenode(){
|
||||
return cy.get('button[mattreenodetoggle]').eq(0)
|
||||
}
|
||||
|
||||
get Metadatainput(){
|
||||
return cy.get('[data-name="appCasem:description"]').eq(1)
|
||||
}
|
||||
|
||||
get Metadatainputsearch(){
|
||||
return cy.get('[data-name="appCasem:description"]').eq(3)
|
||||
}
|
||||
|
||||
get Metadataconfirm(){
|
||||
return cy.nccontains('button', /^ Save $/i)
|
||||
}
|
||||
|
||||
Suchedokument(name: string){
|
||||
cy.get(Mainpage.searchfield).type(name)
|
||||
cy.get('[aria-label="Start search"]').click( {force: true} )
|
||||
}
|
||||
|
||||
Waitforloading(){
|
||||
cy.get(Mainpage.loadingspinner).should("not.exist");
|
||||
}
|
||||
|
||||
get firstaction(){
|
||||
return cy.get('[title="Actions for Processphase: Registration"]')
|
||||
}
|
||||
|
||||
get translatedocument(){
|
||||
return cy.get('[aria-label="Execute Action: Translate document"]')
|
||||
}
|
||||
|
||||
get startaction(){
|
||||
return cy.nccontains(Mainpage.menutextbutton, "Create action")
|
||||
}
|
||||
|
||||
get adddokument(){
|
||||
return cy.nccontains(" Add document to action ")
|
||||
}
|
||||
|
||||
get adddokumenttocase(){
|
||||
return cy.nccontains(" Add to case ")
|
||||
}
|
||||
|
||||
get confirmtranslate(){
|
||||
return cy.nccontains('button', "Translate")
|
||||
}
|
||||
|
||||
Checkfirststarted(){
|
||||
cy.get('[class="node exists"]').get('[title="Actions for Processphase: Registration"]')
|
||||
}
|
||||
|
||||
get fileinput(){
|
||||
return cy.get('input[type="file"]')
|
||||
}
|
||||
|
||||
get attachdokumentclass(){
|
||||
return cy.get('[id="mat-select-0"]')
|
||||
}
|
||||
|
||||
get listitem(){
|
||||
return cy.get(Mainpage.listitem)
|
||||
}
|
||||
|
||||
get tile(){
|
||||
return cy.get(Mainpage.tile)
|
||||
}
|
||||
|
||||
get notification(){
|
||||
return cy.nccontains("notifications")
|
||||
get matmdctooltiptriggersettings() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'settings');
|
||||
}
|
||||
get dummybutton() {
|
||||
return cy.nccontains(Mainpage.menubutton, 'Upload document');
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { Util } from "../util";
|
||||
|
||||
export class Mainpage {
|
||||
|
||||
}
|
||||
232
mainpage.po.ts_something
Normal file
232
mainpage.po.ts_something
Normal file
@@ -0,0 +1,232 @@
|
||||
import { Util } from "../util";
|
||||
|
||||
export class Mainpage {
|
||||
static button = ".mdc-button"
|
||||
static menubutton = ".mat-mdc-menu-item"
|
||||
static menutextbutton = ".mat-mdc-menu-item-text"
|
||||
static openmenu = ".mat-mdc-menu-trigger"
|
||||
static navbuttons = ".mat-mdc-tooltip-trigger"
|
||||
static inputfield = ".mat-mdc-input-element"
|
||||
static panelbutton = ".cmdsk-wlcm__panel-action" //cmdsk-wlcm__panel-action
|
||||
static yuvform = ".yuv-object-form-element"
|
||||
static autocomplete = ".mat-mdc-autocomplete-panel"
|
||||
static calender = ".calender"
|
||||
static checkbox = ".mdc-checkbox"
|
||||
static formcategory = ".main"
|
||||
static buttontext = ".mdc-button__label"
|
||||
static tab = ".mdc-tab"
|
||||
static casefunction = ".mdc-evolution-chip__action"
|
||||
static documentmenubutton = ".cdk-menu-item"
|
||||
static searchfield = ".search"
|
||||
static loadingspinner = ".mat-mdc-progress-spinner"
|
||||
static listitem = ".mdc-list-item"
|
||||
static tile = ".tile"
|
||||
|
||||
static treenode = ".mat-tree-node"
|
||||
|
||||
|
||||
get Uploadbutton() {
|
||||
return cy.nccontains(Mainpage.menubutton, 'Upload document');
|
||||
}
|
||||
|
||||
get Casecreatebutton() {
|
||||
return cy.nccontains(Mainpage.menubutton, ' Create case ');
|
||||
}
|
||||
|
||||
get Openbutton() {
|
||||
return cy.nccontains(Mainpage.openmenu, "add");
|
||||
}
|
||||
|
||||
get Navbuttons() {
|
||||
return cy.get(Mainpage.navbuttons);
|
||||
}
|
||||
|
||||
get Homebutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, 'home')
|
||||
}
|
||||
|
||||
get Casenavbutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, 'cases')
|
||||
}
|
||||
|
||||
get Dokumentenavbutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, 'description')
|
||||
}
|
||||
|
||||
get Deletebutton(){
|
||||
return cy.nccontains(Mainpage.documentmenubutton, 'delete')
|
||||
}
|
||||
|
||||
Casedeletionbutton(selector: string){
|
||||
return cy.contains(selector).parent().parent().parent().find(Mainpage.navbuttons).eq(0)
|
||||
}
|
||||
|
||||
|
||||
get Kebabbutton(){
|
||||
return cy.ncnccontains(Mainpage.openmenu, 'more_vert')
|
||||
}
|
||||
|
||||
get Deleteworkspacebutton(){
|
||||
return cy.nccontains(Mainpage.menubutton, 'Delete workspace')
|
||||
}
|
||||
|
||||
get Confirmbutton(){
|
||||
return cy.nccontains(Mainpage.button, 'Confirm')
|
||||
}
|
||||
|
||||
get Deleteconfirmbutton(){
|
||||
return cy.nccontains(Mainpage.button, 'Delete')
|
||||
}
|
||||
|
||||
get Inputfield() {
|
||||
return cy.get(Mainpage.inputfield);
|
||||
}
|
||||
|
||||
get Panelbutton() {
|
||||
return cy.get(Mainpage.panelbutton);
|
||||
}
|
||||
|
||||
get CasePanelbutton() {
|
||||
return cy.nccontains(Mainpage.panelbutton, 'case')
|
||||
}
|
||||
|
||||
get Yuvform(){
|
||||
return cy.get(Mainpage.yuvform)
|
||||
}
|
||||
|
||||
Caseform(selector: string){
|
||||
return cy.nccontains(Mainpage.yuvform, selector)
|
||||
}
|
||||
|
||||
get Autocomplete(){
|
||||
return cy.get(Mainpage.autocomplete)
|
||||
}
|
||||
|
||||
Caseformcalender(selector: string){
|
||||
return cy.nccontains(Mainpage.yuvform, selector).find(Mainpage.calender)
|
||||
}
|
||||
|
||||
get Formdateselect(){
|
||||
return cy.nccontains('button', "Select")
|
||||
}
|
||||
|
||||
get Checkbox(){
|
||||
return cy.get(Mainpage.checkbox)
|
||||
}
|
||||
|
||||
|
||||
Formcategory(selector: string){
|
||||
return cy.nccontains(Mainpage.formcategory, selector)
|
||||
}
|
||||
|
||||
get Formconfirm(){
|
||||
return cy.nccontains('button', /^ Create $/i)
|
||||
}
|
||||
|
||||
get Historytab(){
|
||||
return cy.nccontains(Mainpage.tab, "history")
|
||||
}
|
||||
|
||||
get Metadatatab(){
|
||||
return cy.nccontains(Mainpage.tab, "Metadata")
|
||||
}
|
||||
|
||||
get Renamebutton(){
|
||||
return cy.nccontains(Mainpage.navbuttons, "Rename")
|
||||
}
|
||||
|
||||
get Renamefield(){
|
||||
return cy.get('yuv-string[formcontrolname="name"] input')
|
||||
}
|
||||
|
||||
get Renameconfirm(){
|
||||
return cy.nccontains(Mainpage.button, "Rename")
|
||||
}
|
||||
|
||||
|
||||
CheckAIfunction(wantedfunction: string){
|
||||
return cy.nccontains(Mainpage.casefunction, wantedfunction)
|
||||
}
|
||||
|
||||
CheckAIlogo(){
|
||||
return cy.nccontains("robot_2")
|
||||
}
|
||||
|
||||
get sortingbutton(){
|
||||
return cy.nccontains("swap_vert")
|
||||
}
|
||||
|
||||
|
||||
get firsttreenode(){
|
||||
return cy.get('button[mattreenodetoggle]').eq(0)
|
||||
}
|
||||
|
||||
get Metadatainput(){
|
||||
return cy.get('[data-name="appCasem:description"]').eq(1)
|
||||
}
|
||||
|
||||
get Metadatainputsearch(){
|
||||
return cy.get('[data-name="appCasem:description"]').eq(3)
|
||||
}
|
||||
|
||||
get Metadataconfirm(){
|
||||
return cy.nccontains('button', /^ Save $/i)
|
||||
}
|
||||
|
||||
Suchedokument(name: string){
|
||||
cy.get(Mainpage.searchfield).type(name)
|
||||
cy.get('[aria-label="Start search"]').click( {force: true} )
|
||||
}
|
||||
|
||||
Waitforloading(){
|
||||
cy.get(Mainpage.loadingspinner).should("not.exist");
|
||||
}
|
||||
|
||||
get firstaction(){
|
||||
return cy.get('[title="Actions for Processphase: Registration"]')
|
||||
}
|
||||
|
||||
get translatedocument(){
|
||||
return cy.get('[aria-label="Execute Action: Translate document"]')
|
||||
}
|
||||
|
||||
get startaction(){
|
||||
return cy.nccontains(Mainpage.menutextbutton, "Create action")
|
||||
}
|
||||
|
||||
get adddokument(){
|
||||
return cy.nccontains(" Add document to action ")
|
||||
}
|
||||
|
||||
get adddokumenttocase(){
|
||||
return cy.nccontains(" Add to case ")
|
||||
}
|
||||
|
||||
get confirmtranslate(){
|
||||
return cy.nccontains('button', "Translate")
|
||||
}
|
||||
|
||||
Checkfirststarted(){
|
||||
cy.get('[class="node exists"]').get('[title="Actions for Processphase: Registration"]')
|
||||
}
|
||||
|
||||
get fileinput(){
|
||||
return cy.get('input[type="file"]')
|
||||
}
|
||||
|
||||
get attachdokumentclass(){
|
||||
return cy.get('[id="mat-select-0"]')
|
||||
}
|
||||
|
||||
get listitem(){
|
||||
return cy.get(Mainpage.listitem)
|
||||
}
|
||||
|
||||
get tile(){
|
||||
return cy.get(Mainpage.tile)
|
||||
}
|
||||
|
||||
get notification(){
|
||||
return cy.nccontains("notifications")
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.openmenu.click();
|
||||
mainpage.menubutton.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.treenode.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.navbuttons.click();
|
||||
mainpage.inputfield.click();
|
||||
mainpage.matmdctooltiptriggersettings.click();
|
||||
mainpage.matbuttontogglebuttonsystem.click();
|
||||
mainpage.matbuttontogglebuttonclass.click();
|
||||
mainpage.schreibensieihreanfrageanclaude.click();
|
||||
mainpage.fontbaseboldkopieren.click();
|
||||
mainpage.matmdctooltiptriggersettings.click();
|
||||
mainpage.matbuttontogglebuttonsystem.click();
|
||||
mainpage.matbuttontogglebuttondark.click();
|
||||
mainpage.matmdctooltiptriggermove_to_inbox.click();
|
||||
mainpage.matmdctooltiptriggerlibrary_books.click();
|
||||
mainpage.matmdctooltiptriggercloud_circle.click();
|
||||
mainpage.matmdcinputelement.click();
|
||||
mainpage.startsearchsearch.click();
|
||||
|
||||
320
server.ts
320
server.ts
@@ -9,99 +9,259 @@ const PORT = 3000;
|
||||
const OUTPUT_FILE = path.join(__dirname, "recorded_clicks.ts");
|
||||
const SUGGESTIONS_FILE = path.join(__dirname, "suggestions.txt");
|
||||
|
||||
// Dynamically find and load the first .po.ts file in the same folder
|
||||
function loadPageObject(): Record<string, string> {
|
||||
const files = fs.readdirSync(__dirname).filter(f => f.endsWith(".po.ts"));
|
||||
// ─── Parse .po.ts file into structured data ───────────────────────────────────
|
||||
|
||||
if (files.length === 0) {
|
||||
console.warn("No .po.ts file found in server directory!");
|
||||
return {};
|
||||
}
|
||||
|
||||
const filePath = path.join(__dirname, files[0]);
|
||||
console.log(`Loading page object from: ${filePath}`);
|
||||
|
||||
const mod = require(filePath);
|
||||
const exportedClass = Object.values(mod)[0] as any;
|
||||
|
||||
const selectors: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(exportedClass)) {
|
||||
if (typeof value === "string") {
|
||||
selectors[key] = value as string;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Loaded ${Object.keys(selectors).length} selectors.`);
|
||||
return selectors;
|
||||
interface ParsedPageObject {
|
||||
filePath: string;
|
||||
statics: Record<string, string>; // name -> selector value
|
||||
getFunctions: ParsedGetFn[];
|
||||
}
|
||||
|
||||
function findMatches(data: any, selectors: Record<string, string>): string[] {
|
||||
const results: string[] = [];
|
||||
interface ParsedGetFn {
|
||||
name: string;
|
||||
body: string; // full body text
|
||||
referencedStatics: string[]; // static variable names used in body
|
||||
nccontainsText: string | null; // text in nccontains() if present
|
||||
}
|
||||
|
||||
for (const [name, selector] of Object.entries(selectors)) {
|
||||
if (selector.startsWith(".")) {
|
||||
const className = selector.replace(".", "");
|
||||
if (data.classes.includes(className)) {
|
||||
results.push(name);
|
||||
function parsePageObject(): ParsedPageObject {
|
||||
const poFiles = fs.readdirSync(__dirname).filter(f => f.endsWith(".po.ts"));
|
||||
if (poFiles.length === 0) throw new Error("No .po.ts file found!");
|
||||
|
||||
const filePath = path.join(__dirname, poFiles[0]);
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
const lines = content.split("\n");
|
||||
|
||||
const statics: Record<string, string> = {};
|
||||
const getFunctions: ParsedGetFn[] = [];
|
||||
|
||||
let i = 0;
|
||||
while (i < lines.length) {
|
||||
const line = lines[i].trimStart();
|
||||
|
||||
// Parse static declarations: static foo = ".some-class"
|
||||
const staticMatch = line.match(/^static\s+(\w+)\s*=\s*["'](.+?)["']/);
|
||||
if (staticMatch) {
|
||||
statics[staticMatch[1]] = staticMatch[2];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse get functions: get FooBar() {
|
||||
const getMatch = line.match(/^get\s+(\w+)\s*\(/);
|
||||
if (getMatch) {
|
||||
const fnName = getMatch[1];
|
||||
const bodyLines: string[] = [];
|
||||
let depth = 0;
|
||||
while (i < lines.length) {
|
||||
const l = lines[i];
|
||||
bodyLines.push(l);
|
||||
for (const ch of l) {
|
||||
if (ch === "{") depth++;
|
||||
if (ch === "}") depth--;
|
||||
}
|
||||
i++;
|
||||
if (depth === 0 && bodyLines.length > 1) break;
|
||||
}
|
||||
const body = bodyLines.join("\n");
|
||||
|
||||
// Find which static variables are referenced
|
||||
const referencedStatics = Object.keys(statics).filter(s =>
|
||||
body.includes(s)
|
||||
);
|
||||
|
||||
// Extract nccontains text if present: nccontains(Mainpage.foo, 'some text')
|
||||
const ncMatch = body.match(/nccontains\s*\([^,]+,\s*['"](.+?)['"]\s*\)/);
|
||||
const nccontainsText = ncMatch ? ncMatch[1] : null;
|
||||
|
||||
getFunctions.push({ name: fnName, body, referencedStatics, nccontainsText });
|
||||
continue;
|
||||
}
|
||||
if (data.ariaLabel && selector === data.ariaLabel) {
|
||||
results.push(name);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
console.log(`Parsed ${Object.keys(statics).length} statics, ${getFunctions.length} get functions.`);
|
||||
return { filePath, statics, getFunctions };
|
||||
}
|
||||
|
||||
// ─── Matching logic ────────────────────────────────────────────────────────────
|
||||
|
||||
interface MatchResult {
|
||||
type: "full_match" | "static_only" | "no_match";
|
||||
fnName?: string; // for full_match
|
||||
staticName?: string; // for static_only and no_match (if static exists)
|
||||
selectorVar?: string; // for static_only (to build the new get fn)
|
||||
}
|
||||
|
||||
function findMatch(data: any, po: ParsedPageObject): MatchResult {
|
||||
const rawText = data.text ? data.text.split("\n")[0].trim() : null;
|
||||
|
||||
// Step 1: find matching static names by class or aria-label
|
||||
const matchingStatics: string[] = [];
|
||||
for (const [name, value] of Object.entries(po.statics)) {
|
||||
const classMatch = value.startsWith(".") && data.classes.includes(value.slice(1));
|
||||
const ariaMatch = data.ariaLabel && value === data.ariaLabel;
|
||||
if (classMatch || ariaMatch) {
|
||||
matchingStatics.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
if (matchingStatics.length === 0) {
|
||||
return { type: "no_match" };
|
||||
}
|
||||
|
||||
// Step 2: find a get function that references one of those statics AND has matching text
|
||||
for (const fn of po.getFunctions) {
|
||||
const referencesMatch = fn.referencedStatics.some(s => matchingStatics.includes(s));
|
||||
if (!referencesMatch) continue;
|
||||
|
||||
// If we have text, require nccontains to match it
|
||||
if (rawText) {
|
||||
if (fn.nccontainsText && fn.nccontainsText.toLowerCase() === rawText.toLowerCase()) {
|
||||
return { type: "full_match", fnName: fn.name };
|
||||
}
|
||||
} else {
|
||||
// No text — any get function referencing the static is good enough
|
||||
return { type: "full_match", fnName: fn.name };
|
||||
}
|
||||
}
|
||||
|
||||
// Static matched but no get function with matching text found
|
||||
return {
|
||||
type: "static_only",
|
||||
staticName: matchingStatics[0],
|
||||
selectorVar: `Mainpage.${matchingStatics[0]}`,
|
||||
};
|
||||
}
|
||||
|
||||
function appendToOutput(matches: string[]) {
|
||||
const lines = matches.map(name => `mainpage.${name}.click();`);
|
||||
fs.appendFileSync(OUTPUT_FILE, lines.join("\n") + "\n");
|
||||
// ─── File insertion ────────────────────────────────────────────────────────────
|
||||
|
||||
function insertGetFunction(filePath: string, getBlock: string) {
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
const fileLines = content.split("\n");
|
||||
|
||||
// Find the last static line
|
||||
let lastStaticIndex = -1;
|
||||
for (let i = 0; i < fileLines.length; i++) {
|
||||
if (fileLines[i].trimStart().startsWith("static ")) lastStaticIndex = i;
|
||||
}
|
||||
|
||||
// Find first get after static block
|
||||
let firstGetIndex = -1;
|
||||
for (let i = lastStaticIndex + 1; i < fileLines.length; i++) {
|
||||
if (fileLines[i].trimStart().startsWith("get ")) { firstGetIndex = i; break; }
|
||||
}
|
||||
|
||||
if (firstGetIndex === -1) {
|
||||
console.warn("Could not find first get function, aborting insert.");
|
||||
return;
|
||||
}
|
||||
|
||||
const getLines = getBlock.split("\n");
|
||||
fileLines.splice(firstGetIndex, 0, "", ...getLines);
|
||||
fs.writeFileSync(filePath, fileLines.join("\n"), "utf-8");
|
||||
}
|
||||
|
||||
function appendSuggestion(data: any) {
|
||||
function insertStaticAndGet(filePath: string, staticLine: string, getBlock: string) {
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
const fileLines = content.split("\n");
|
||||
|
||||
// Find last static line
|
||||
let lastStaticIndex = -1;
|
||||
for (let i = 0; i < fileLines.length; i++) {
|
||||
if (fileLines[i].trimStart().startsWith("static ")) lastStaticIndex = i;
|
||||
}
|
||||
|
||||
if (lastStaticIndex === -1) {
|
||||
console.warn("Could not find static block, aborting insert.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find first get after static block
|
||||
let firstGetIndex = -1;
|
||||
for (let i = lastStaticIndex + 1; i < fileLines.length; i++) {
|
||||
if (fileLines[i].trimStart().startsWith("get ")) { firstGetIndex = i; break; }
|
||||
}
|
||||
|
||||
if (firstGetIndex === -1) {
|
||||
console.warn("Could not find first get function, aborting insert.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert static
|
||||
fileLines.splice(lastStaticIndex + 1, 0, ` ${staticLine}`);
|
||||
|
||||
// Insert get (shifted by 1)
|
||||
const getLines = getBlock.split("\n");
|
||||
fileLines.splice(firstGetIndex + 1, 0, "", ...getLines);
|
||||
|
||||
fs.writeFileSync(filePath, fileLines.join("\n"), "utf-8");
|
||||
}
|
||||
|
||||
// ─── Main handler ──────────────────────────────────────────────────────────────
|
||||
|
||||
function buildGetFnName(data: any): string {
|
||||
const rawText = data.text ? data.text.split("\n")[0].trim() : null;
|
||||
const firstClass = data.classes.length > 0 ? data.classes[0] : null;
|
||||
|
||||
// Generate a name from aria-label or first class
|
||||
const name = data.ariaLabel
|
||||
const baseName = data.ariaLabel
|
||||
? data.ariaLabel.replace(/\s+/g, "").toLowerCase()
|
||||
: firstClass
|
||||
? firstClass.replace(/[-_.]/g, "").toLowerCase()
|
||||
: "unknown";
|
||||
|
||||
const lines: string[] = [];
|
||||
lines.push(`// --- Unmatched click (tag: <${data.tag}>, text: "${data.text}") ---`);
|
||||
lines.push(`// Check if these exist and add to your page object:`);
|
||||
if (firstClass) lines.push(`static ${name}class = ".${firstClass}"`);
|
||||
if (data.id) lines.push(`static ${name}id = "#${data.id}"`);
|
||||
if (data.ariaLabel) lines.push(`static ${name}aria = "[aria-label='${data.ariaLabel}']"`);
|
||||
lines.push(``);
|
||||
lines.push(`// Suggested get function:`);
|
||||
|
||||
// Selector: aria if available, otherwise class
|
||||
const selectorVar = data.ariaLabel ? `Mainpage.${name}aria` : `Mainpage.${name}class`;
|
||||
|
||||
// Always include text and tag if available
|
||||
const hasText = data.text && data.text.length > 0;
|
||||
const filterParts: string[] = [];
|
||||
if (data.tag) filterParts.push(`data.tag: "${data.tag}"`);
|
||||
if (hasText) filterParts.push(`text: "${data.text}"`);
|
||||
|
||||
lines.push(`get ${name}() {`);
|
||||
if (hasText) {
|
||||
lines.push(` return cy.nccontains(${selectorVar}, '${data.text}');`);
|
||||
} else {
|
||||
lines.push(` return cy.get(${selectorVar});`);
|
||||
}
|
||||
lines.push(`}`);
|
||||
lines.push(``);
|
||||
lines.push(`// ------------------------------------------------`);
|
||||
lines.push(``);
|
||||
|
||||
fs.appendFileSync(SUGGESTIONS_FILE, lines.join("\n") + "\n");
|
||||
return rawText ? baseName + rawText.replace(/\s+/g, "").toLowerCase() : baseName;
|
||||
}
|
||||
|
||||
// Load selectors once at startup
|
||||
const selectors = loadPageObject();
|
||||
function handleClick(data: any) {
|
||||
const po = parsePageObject();
|
||||
const match = findMatch(data, po);
|
||||
const rawText = data.text ? data.text.split("\n")[0].trim() : null;
|
||||
const hasText = rawText && rawText.length > 0;
|
||||
const firstClass = data.classes.length > 0 ? data.classes[0] : null;
|
||||
|
||||
if (match.type === "full_match") {
|
||||
// Perfect — use existing function
|
||||
console.log(` >> Full match: mainpage.${match.fnName}.click();`);
|
||||
fs.appendFileSync(OUTPUT_FILE, `mainpage.${match.fnName}.click();\n`);
|
||||
|
||||
} else if (match.type === "static_only") {
|
||||
// Static exists, just create the get function
|
||||
const getFnName = buildGetFnName(data);
|
||||
const getBody = hasText
|
||||
? ` return cy.nccontains(${match.selectorVar}, '${rawText}');`
|
||||
: ` return cy.get(${match.selectorVar});`;
|
||||
const getBlock = ` get ${getFnName}() {\n${getBody}\n }`;
|
||||
|
||||
console.log(` >> Static match, inserting get function: ${getFnName}`);
|
||||
insertGetFunction(po.filePath, getBlock);
|
||||
fs.appendFileSync(OUTPUT_FILE, `mainpage.${getFnName}.click();\n`);
|
||||
fs.appendFileSync(SUGGESTIONS_FILE, `// Inserted get function (static already existed)\n${getBlock}\n// ----\n\n`);
|
||||
|
||||
} else {
|
||||
// No match at all — create both static and get function
|
||||
const baseName = data.ariaLabel
|
||||
? data.ariaLabel.replace(/\s+/g, "").toLowerCase()
|
||||
: firstClass
|
||||
? firstClass.replace(/[-_.]/g, "").toLowerCase()
|
||||
: "unknown";
|
||||
const getFnName = buildGetFnName(data);
|
||||
const selectorVar = data.ariaLabel ? `Mainpage.${baseName}aria` : `Mainpage.${baseName}class`;
|
||||
const staticValue = data.ariaLabel ? `"[aria-label='${data.ariaLabel}']"` : `".${firstClass}"`;
|
||||
const staticName = data.ariaLabel ? `${baseName}aria` : `${baseName}class`;
|
||||
const staticLine = `static ${staticName} = ${staticValue}`;
|
||||
const getBody = hasText
|
||||
? ` return cy.nccontains(${selectorVar}, '${rawText}');`
|
||||
: ` return cy.get(${selectorVar});`;
|
||||
const getBlock = ` get ${getFnName}() {\n${getBody}\n }`;
|
||||
|
||||
console.log(` >> No match, inserting static + get function: ${getFnName}`);
|
||||
insertStaticAndGet(po.filePath, staticLine, getBlock);
|
||||
fs.appendFileSync(OUTPUT_FILE, `mainpage.${getFnName}.click();\n`);
|
||||
fs.appendFileSync(SUGGESTIONS_FILE, `// Inserted static + get\n ${staticLine}\n${getBlock}\n// ----\n\n`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Server ────────────────────────────────────────────────────────────────────
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
@@ -116,7 +276,6 @@ const server = http.createServer((req, res) => {
|
||||
|
||||
if (req.method === "POST" && req.url === "/record") {
|
||||
let body = "";
|
||||
|
||||
req.on("data", (chunk) => (body += chunk));
|
||||
req.on("end", () => {
|
||||
try {
|
||||
@@ -129,19 +288,9 @@ const server = http.createServer((req, res) => {
|
||||
console.log("Classes: ", data.classes.join(", "));
|
||||
console.log("Text: ", data.text);
|
||||
|
||||
const matches = findMatches(data, selectors);
|
||||
|
||||
if (matches.length > 0) {
|
||||
console.log("Matches:");
|
||||
matches.forEach(m => console.log(` >> mainpage.${m}.click();`));
|
||||
appendToOutput(matches);
|
||||
} else {
|
||||
console.log(" >> No match — writing to suggestions.txt");
|
||||
appendSuggestion(data);
|
||||
}
|
||||
handleClick(data);
|
||||
|
||||
console.log("----------------------");
|
||||
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ status: "ok" }));
|
||||
} catch (err: any) {
|
||||
@@ -158,4 +307,5 @@ const server = http.createServer((req, res) => {
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`Cypress Recorder server running on http://localhost:${PORT}`);
|
||||
console.log(`Watching for clicks...`);
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
// --- Inserted (tag: <button>, text: "settings") ---
|
||||
static matmdctooltiptriggerclass = ".mat-mdc-tooltip-trigger"
|
||||
get matmdctooltiptriggersettings() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'settings');
|
||||
}
|
||||
// ------------------------------------------------
|
||||
|
||||
// --- Inserted (tag: <button>, text: "System") ---
|
||||
static matbuttontogglebuttonclass = ".mat-button-toggle-button"
|
||||
get matbuttontogglebuttonsystem() {
|
||||
return cy.nccontains(Mainpage.matbuttontogglebuttonclass, 'System');
|
||||
}
|
||||
// ------------------------------------------------
|
||||
|
||||
// --- Inserted (tag: <div>, text: "null") ---
|
||||
static schreibensieihreanfrageanclaudearia = "[aria-label='Schreiben Sie Ihre Anfrage an Claude']"
|
||||
get schreibensieihreanfrageanclaude() {
|
||||
return cy.get(Mainpage.schreibensieihreanfrageanclaudearia);
|
||||
}
|
||||
// ------------------------------------------------
|
||||
|
||||
// --- Inserted (tag: <button>, text: "Kopieren") ---
|
||||
static fontbaseboldclass = ".font-base-bold"
|
||||
get fontbaseboldkopieren() {
|
||||
return cy.nccontains(Mainpage.fontbaseboldclass, 'Kopieren');
|
||||
}
|
||||
// ------------------------------------------------
|
||||
|
||||
// Inserted static + get
|
||||
static matmdctooltiptriggerclass = ".mat-mdc-tooltip-trigger"
|
||||
get matmdctooltiptriggersettings() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'settings');
|
||||
}
|
||||
// ----
|
||||
|
||||
// Inserted static + get
|
||||
static matbuttontogglebuttonclass = ".mat-button-toggle-button"
|
||||
get matbuttontogglebuttonsystem() {
|
||||
return cy.nccontains(Mainpage.matbuttontogglebuttonclass, 'System');
|
||||
}
|
||||
// ----
|
||||
|
||||
// Inserted get function (static already existed)
|
||||
get matbuttontogglebuttondark() {
|
||||
return cy.nccontains(Mainpage.matbuttontogglebuttonclass, 'Dark');
|
||||
}
|
||||
// ----
|
||||
|
||||
// Inserted get function (static already existed)
|
||||
get matmdctooltiptriggermove_to_inbox() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'move_to_inbox');
|
||||
}
|
||||
// ----
|
||||
|
||||
// Inserted get function (static already existed)
|
||||
get matmdctooltiptriggerlibrary_books() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'library_books');
|
||||
}
|
||||
// ----
|
||||
|
||||
// Inserted get function (static already existed)
|
||||
get matmdctooltiptriggercloud_circle() {
|
||||
return cy.nccontains(Mainpage.matmdctooltiptriggerclass, 'cloud_circle');
|
||||
}
|
||||
// ----
|
||||
|
||||
// Inserted static + get
|
||||
static matmdcinputelementclass = ".mat-mdc-input-element"
|
||||
get matmdcinputelement() {
|
||||
return cy.get(Mainpage.matmdcinputelementclass);
|
||||
}
|
||||
// ----
|
||||
|
||||
// Inserted static + get
|
||||
static startsearcharia = "[aria-label='Start search']"
|
||||
get startsearchsearch() {
|
||||
return cy.nccontains(Mainpage.startsearcharia, 'search');
|
||||
}
|
||||
// ----
|
||||
|
||||
|
||||
Reference in New Issue
Block a user