diff --git a/v3/cypress/e2e/formula/formula-errors.spec.ts b/v3/cypress/e2e/formula/formula-errors.spec.ts index 07f65e5ad1..c1d27b5014 100644 --- a/v3/cypress/e2e/formula/formula-errors.spec.ts +++ b/v3/cypress/e2e/formula/formula-errors.spec.ts @@ -3,7 +3,7 @@ import { FormulaHelper as fh } from "../../support/helpers/formula-helper" context("Formula Engine", () => { describe("Errors Formula Tests", () => { it("Check invalid functions", () => { - fh.visitURL("?sample=four&dashboard") + fh.visitURL("?sample=four") fh.addNewAttribute() fh.renameAttribute("newAttr", "Formula") fh.addFormula("Formula", "count(aaa)") @@ -22,7 +22,8 @@ context("Formula Engine", () => { "❌ Undefined function c", "❌ Undefined function c" ]) - fh.editFormula("Formula", "count(a") + // need to add {del} because CodeMirror auto-matches parentheses + fh.editFormula("Formula", "count(a{del}") fh.verifyValues("Formula", [ "❌ Syntax error: 'Parenthesis ) expected (char 8)'", "❌ Syntax error: 'Parenthesis ) expected (char 8)'", diff --git a/v3/cypress/support/e2e.ts b/v3/cypress/support/e2e.ts index 88b1cd44d3..6ac38fe52c 100644 --- a/v3/cypress/support/e2e.ts +++ b/v3/cypress/support/e2e.ts @@ -22,6 +22,9 @@ import "./commands" // add code coverage support import "@cypress/code-coverage/support" +// add support for dispatching native events (https://github.com/dmtrKovalenko/cypress-real-events) +import "cypress-real-events" + // https://github.com/quasarframework/quasar/issues/2233#issuecomment-1006506083 Cypress.on("uncaught:exception", err => !err.message.includes("ResizeObserver")) diff --git a/v3/cypress/support/elements/table-tile.ts b/v3/cypress/support/elements/table-tile.ts index 206af0d1a8..59c876d80b 100644 --- a/v3/cypress/support/elements/table-tile.ts +++ b/v3/cypress/support/elements/table-tile.ts @@ -387,19 +387,21 @@ export const TableTileElements = { }, addFormulaInModal(attributeName: string, formula: string) { cy.get("[data-testid=attr-name-input]").invoke("attr", "value").should("eq", attributeName) - cy.get("[data-testid=formula-editor-input]").type(formula, {force:true}) + cy.get("[data-testid=formula-editor-input] .cm-content").should("be.visible").and("have.focus") + cy.get("[data-testid=formula-editor-input] .cm-content").realType(formula) cy.get("[data-testid=Apply-button]").click() cy.get("[data-testid=attr-name-input]").should("not.exist") }, clearFormulaInModal(attributeName: string) { cy.get("[data-testid=attr-name-input]").invoke("attr", "value").should("eq", attributeName) - cy.get("[data-testid=formula-editor-input]").type(`{selectAll}{del}`) + cy.get("[data-testid=formula-editor-input] .cm-content").realPress(["Meta", "A"]) + cy.get("[data-testid=formula-editor-input] .cm-content").realType("{del}") cy.get("[data-testid=Apply-button]").click() cy.get("[data-testid=attr-name-input]").should("not.exist") }, checkFormulaInModal(attributeName: string, formula: string) { cy.get("[data-testid=attr-name-input]").invoke("attr", "value").should("eq", attributeName) - cy.get("[data-testid=formula-editor-input]").should("have.text", formula) + cy.get("[data-testid=formula-editor-input] .cm-content").should("have.text", formula) cy.get("[data-testid=Cancel-button]").click() cy.get("[data-testid=attr-name-input]").should("not.exist") }, diff --git a/v3/cypress/tsconfig.json b/v3/cypress/tsconfig.json index b605197401..ca6955e465 100644 --- a/v3/cypress/tsconfig.json +++ b/v3/cypress/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../tsconfig.json", "compilerOptions": { "sourceMap": false, - "types": ["cypress"] + "types": ["cypress", "cypress-real-events"] }, "include": [ "./**/*" diff --git a/v3/package-lock.json b/v3/package-lock.json index 1bc7324fc5..76ae7ee840 100644 --- a/v3/package-lock.json +++ b/v3/package-lock.json @@ -91,6 +91,7 @@ "clean-webpack-plugin": "^4.0.0", "css-loader": "^7.1.2", "cypress": "^13.13.3", + "cypress-real-events": "^1.13.0", "dotenv-webpack": "^8.1.0", "eslint": "^8.57.0", "eslint-config-react": "^1.1.7", @@ -10294,6 +10295,15 @@ "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, + "node_modules/cypress-real-events": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/cypress-real-events/-/cypress-real-events-1.13.0.tgz", + "integrity": "sha512-LoejtK+dyZ1jaT8wGT5oASTPfsNV8/ClRp99ruN60oPj8cBJYod80iJDyNwfPAu4GCxTXOhhAv9FO65Hpwt6Hg==", + "dev": true, + "peerDependencies": { + "cypress": "^4.x || ^5.x || ^6.x || ^7.x || ^8.x || ^9.x || ^10.x || ^11.x || ^12.x || ^13.x" + } + }, "node_modules/cypress/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -32724,6 +32734,13 @@ } } }, + "cypress-real-events": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/cypress-real-events/-/cypress-real-events-1.13.0.tgz", + "integrity": "sha512-LoejtK+dyZ1jaT8wGT5oASTPfsNV8/ClRp99ruN60oPj8cBJYod80iJDyNwfPAu4GCxTXOhhAv9FO65Hpwt6Hg==", + "dev": true, + "requires": {} + }, "d3": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", diff --git a/v3/package.json b/v3/package.json index de24db3534..a9de5717e2 100644 --- a/v3/package.json +++ b/v3/package.json @@ -133,6 +133,7 @@ "clean-webpack-plugin": "^4.0.0", "css-loader": "^7.1.2", "cypress": "^13.13.3", + "cypress-real-events": "^1.13.0", "dotenv-webpack": "^8.1.0", "eslint": "^8.57.0", "eslint-config-react": "^1.1.7", diff --git a/v3/src/components/common/formula-editor.tsx b/v3/src/components/common/formula-editor.tsx index f325055e16..3269245c7f 100644 --- a/v3/src/components/common/formula-editor.tsx +++ b/v3/src/components/common/formula-editor.tsx @@ -232,11 +232,17 @@ export function FormulaEditor({ formula, setFormula, options: _options }: IProps const { attributes = true, constants = true, functions = true, globals = true, specials = true } = options || {} const fullOptions: ICompletionOptions = { attributes, constants, functions, globals, specials } view.dispatch({ effects: cmUpdateOptionsEffect.of(fullOptions) }) + + // https://discuss.codemirror.net/t/how-to-autofocus-in-cm6/2966 + const focusTimer = setInterval(() => { + view.focus() + if (view.hasFocus) clearInterval(focusTimer) + }, 100) }, [dataSet, options]) const handleFormulaChange = (value: string, viewUpdate: ViewUpdate) => setFormula(value) - return }