diff --git a/cypress-tests/cypress/constants/selectors/workspaceConstants.js b/cypress-tests/cypress/constants/selectors/workspaceConstants.js index 3f2a0e9275..de38a10273 100644 --- a/cypress-tests/cypress/constants/selectors/workspaceConstants.js +++ b/cypress-tests/cypress/constants/selectors/workspaceConstants.js @@ -27,4 +27,7 @@ export const workspaceConstantsSelectors = { constDeleteButton: (constName) => { return `[data-cy="${cyParamName(constName)}-delete-button"]`; }, + constHideButton: (constName) => { + return `[data-cy="${cyParamName(constName)}-constant-visibility"]`; + }, }; diff --git a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/workspace/workspaceConstants.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/workspace/workspaceConstants.cy.js index 1fc8cab168..989748a159 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/workspace/workspaceConstants.cy.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/workspace/workspaceConstants.cy.js @@ -9,11 +9,9 @@ import { AddNewconstants, } from "Support/utils/workspaceConstants"; import { buttonText } from "Texts/button"; -import { - editAndVerifyWidgetName, -} from "Support/utils/commonWidget"; -import { verifypreview } from "Support/utils/dataSource"; - +import { editAndVerifyWidgetName } from "Support/utils/commonWidget"; +import { verifypreview, createDataQuery } from "Support/utils/dataSource"; +import { dataSourceSelector } from "Selectors/dataSource"; import { selectQueryFromLandingPage, query, @@ -21,12 +19,6 @@ import { } from "Support/utils/queries"; const data = {}; -data.constName = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", ""); -data.newConstvalue = `New ${data.constName}`; -data.constantsName = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", ""); -data.constantsValue = "dJ_8Q~BcaMPd"; -data.appName = `${fake.companyName}-App`; -data.slug = data.appName.toLowerCase().replace(/\s+/g, "-"); describe("Workspace constants", () => { const envVar = Cypress.env("environment"); @@ -36,7 +28,16 @@ describe("Workspace constants", () => { cy.skipWalkthrough(); }); it("Verify workspace constants UI and CRUD operations", () => { - cy.get('[data-cy="icon-workspace-constants"]').click(); + data.constName = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", ""); + data.newConstvalue = `New ${data.constName}`; + data.constantsName = fake.firstName + .toLowerCase() + .replaceAll("[^A-Za-z]", ""); + data.constantsValue = "dJ_8Q~BcaMPd"; + data.appName = `${fake.companyName}-App`; + data.slug = data.appName.toLowerCase().replace(/\s+/g, "-"); + + cy.get(commonSelectors.workspaceConstantsIcon).click(); cy.get(commonSelectors.pageSectionHeader).verifyVisibleElement( "have.text", @@ -88,13 +89,14 @@ describe("Workspace constants", () => { .invoke("attr", "placeholder") .should("eq", "Enter Constant Name"); cy.get(commonSelectors.nameInputField).should("be.visible"); - cy.get(commonSelectors.valueLabel).verifyVisibleElement( - "have.text", - "Value" - ); + cy.get(commonSelectors.valueLabel).should(($el) => { + expect($el.contents().first().text().trim()).to.eq("Value"); + }); + cy.get('[data-cy="encrypted-label"]>').should("be.visible"); + cy.verifyLabel("Encrypted"); cy.get(commonSelectors.valueInputField) .invoke("attr", "placeholder") - .should("eq", "Enter Value"); + .should("eq", "Enter value"); cy.get(commonSelectors.valueInputField).should("be.visible"); cy.get(commonSelectors.cancelButton).verifyVisibleElement( "have.text", @@ -118,6 +120,7 @@ describe("Workspace constants", () => { "Constant name should be between 1 and 32 characters" ); + cy.get(commonSelectors.valueInputField).click(); cy.clearAndType(commonSelectors.valueInputField, " "); cy.get(commonSelectors.valueErrorText).verifyVisibleElement( "have.text", @@ -128,6 +131,7 @@ describe("Workspace constants", () => { cy.get(workspaceConstantsSelectors.addNewConstantButton).click(); cy.clearAndType(commonSelectors.nameInputField, data.constName); + cy.get(commonSelectors.valueInputField).click(); cy.clearAndType(commonSelectors.valueInputField, data.constName); cy.get(workspaceConstantsSelectors.addConstantButton).should("be.enabled"); cy.get(commonSelectors.cancelButton).click(); @@ -137,6 +141,7 @@ describe("Workspace constants", () => { cy.get(workspaceConstantsSelectors.addNewConstantButton).click(); cy.clearAndType(commonSelectors.nameInputField, data.constName); + cy.get(commonSelectors.valueInputField).click(); cy.clearAndType(commonSelectors.valueInputField, data.constName); cy.get(workspaceConstantsSelectors.addConstantButton).click(); cy.verifyToastMessage( @@ -167,6 +172,8 @@ describe("Workspace constants", () => { cy.get( workspaceConstantsSelectors.constantName(data.constName) ).verifyVisibleElement("have.text", data.constName); + + cy.get(workspaceConstantsSelectors.constHideButton(data.constName)).click(); cy.get( workspaceConstantsSelectors.constantValue(data.constName) ).verifyVisibleElement("have.text", data.constName); @@ -189,13 +196,15 @@ describe("Workspace constants", () => { cy.get(commonSelectors.nameInputField) .should("be.visible") .and("be.disabled"); - cy.get(commonSelectors.valueLabel).verifyVisibleElement( - "have.text", - "Value" - ); + cy.get(commonSelectors.valueLabel).should(($el) => { + expect($el.contents().first().text().trim()).to.eq("Value"); + }); cy.get(commonSelectors.valueInputField) + .click() .should("be.visible") .and("have.value", data.constName); + // cy.get(commonSelectors.valueInputField) + cy.get(commonSelectors.cancelButton).verifyVisibleElement( "have.text", "Cancel" @@ -206,6 +215,7 @@ describe("Workspace constants", () => { ); cy.get(workspaceConstantsSelectors.addConstantButton).should("be.disabled"); + cy.get(commonSelectors.valueInputField).click(); cy.clearAndType(commonSelectors.valueInputField, data.newConstvalue); cy.get(workspaceConstantsSelectors.addConstantButton).should("be.enabled"); cy.get(commonSelectors.cancelButton).click(); @@ -214,16 +224,17 @@ describe("Workspace constants", () => { ).verifyVisibleElement("have.text", data.constName); cy.get(workspaceConstantsSelectors.constEditButton(data.constName)).click(); + cy.get(commonSelectors.valueInputField).click(); cy.clearAndType(commonSelectors.valueInputField, data.newConstvalue); cy.get(workspaceConstantsSelectors.addConstantButton).click(); cy.verifyToastMessage( commonSelectors.toastMessage, "Constant updated successfully" ); - cy.get( - workspaceConstantsSelectors.constantValue(data.constName) - ).verifyVisibleElement("have.text", data.newConstvalue); + cy.get(workspaceConstantsSelectors.constantValue(data.constName)) + .should("be.visible") + .and("have.text", data.newConstvalue); cy.get( workspaceConstantsSelectors.constDeleteButton(data.constName) ).click(); @@ -256,77 +267,74 @@ describe("Workspace constants", () => { }); it("should verify the constants resolving value on components and query", () => { - cy.get('[data-cy="icon-workspace-constants"]').click(); - AddNewconstants(data.constantsName, data.constantsValue); - cy.get( - workspaceConstantsSelectors.constantName(data.constantsName) - ).verifyVisibleElement("have.text", data.constantsName); - cy.get( - workspaceConstantsSelectors.constantValue(data.constantsName) - ).verifyVisibleElement("have.text", data.constantsValue); + cy.viewport(1200, 1300); + + data.widgetName = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", ""); + data.appName = `${fake.companyName}-App`; + data.restapilink = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", ""); + data.restapiHeaderKey = fake.firstName + .toLowerCase() + .replaceAll("[^A-Za-z]", ""); + data.restapiHeaderValue = fake.firstName + .toLowerCase() + .replaceAll("[^A-Za-z]", ""); + + cy.get(commonSelectors.workspaceConstantsIcon).click(); + AddNewconstants(data.restapilink, "http://localhost:4000/production"); + AddNewconstants(data.restapiHeaderKey, "customHeader"); + AddNewconstants(data.restapiHeaderValue, "key=value"); cy.get(commonSelectors.homePageLogo).click(); cy.wait("@homePage"); - cy.createApp(data.appName); + cy.apiCreateApp(data.appName); + + cy.getCookie("tj_auth_token").then((cookie) => { + const headers = { + "Tj-Workspace-Id": Cypress.env("workspaceId"), + Cookie: `tj_auth_token=${cookie.value}`, + }; + cy.request({ + method: "GET", + url: `http://localhost:3000/api/app-environments/versions?app_id=${Cypress.env( + "appId" + )}`, + headers: headers, + }).then((response) => { + const appVersions = response.body.appVersions; + const appVersionId = appVersions[0].id; + createDataQuery( + appVersionId, + data.restapilink, + data.restapiHeaderKey, + data.restapiHeaderValue + ); + }); + }); - selectQueryFromLandingPage("runjs", "JavaScript"); - addInputOnQueryField("runjs", `return constants.${data.constantsName}`); - query("preview"); - verifypreview("raw", "dJ_8Q~BcaMPd"); + cy.openApp(); - cy.dragAndDropWidget("Text", 550, 350); - editAndVerifyWidgetName(data.constantsName, []); + cy.get(".custom-toggle-switch>.switch>").eq(3).click(); + + cy.waitForAutoSave(); + cy.dragAndDropWidget("Text", 550, 650); + editAndVerifyWidgetName(data.widgetName, []); cy.waitForAutoSave(); cy.get( '[data-cy="textcomponenttextinput-input-field"]' - ).clearAndTypeOnCodeMirror(`{{constants.${data.constantsName}`); + ).clearAndTypeOnCodeMirror(`{{queries.restapi1.data.message`); cy.forceClickOnCanvas(); cy.waitForAutoSave(); - - common.pinInspector(); - // cy.get(".tooltip-inner").invoke("hide"); - cy.get(commonWidgetSelector.sidebarinspector).click(); - cy.get(commonWidgetSelector.inspectorNodeComponents).click(); - cy.get(commonWidgetSelector.nodeComponent(data.constantsName)).click(); - cy.get('[data-cy="inspector-node-text"] > .mx-2').verifyVisibleElement( - "have.text", - `"dJ_8Q~BcaMPd"` - ); - - cy.get('[data-cy="inspector-node-constants"] > .node-key').click(); - cy.get(`[data-cy="inspector-node-${data.constantsName}"] > .node-key`) - .eq(1) - .verifyVisibleElement("have.text", data.constantsName); + cy.get(dataSourceSelector.queryCreateAndRunButton).click(); cy.get( - `[data-cy="inspector-node-${data.constantsName}"] > .mx-2` - ).verifyVisibleElement("have.text", `"dJ_8Q~BcaMPd"`); + commonWidgetSelector.draggableWidget(data.widgetName) + ).verifyVisibleElement("have.text", "Production environment testing"); - cy.get('[data-cy="button-release"]').click(); - cy.get('[data-cy="yes-button"]').click(); - cy.verifyToastMessage(commonSelectors.toastMessage, "Version v1 released"); - - cy.get(commonWidgetSelector.shareAppButton).click(); - cy.clearAndType(commonWidgetSelector.appNameSlugInput, `${data.slug}`); - cy.wait(1500); - cy.get(commonWidgetSelector.modalCloseButton).click(); - cy.forceClickOnCanvas(); - cy.waitForAutoSave(); - cy.wait(500); cy.openInCurrentTab(commonWidgetSelector.previewButton); cy.wait(4000); cy.get( - commonWidgetSelector.draggableWidget(data.constantsName) - ).verifyVisibleElement("have.text", "dJ_8Q~BcaMPd"); - - cy.get('[data-cy="viewer-page-logo"]').click(); - cy.wait("@homePage"); - cy.visit(`/applications/${data.slug}`); - cy.wait(4000); - - cy.get( - commonWidgetSelector.draggableWidget(data.constantsName) - ).verifyVisibleElement("have.text", "dJ_8Q~BcaMPd"); + commonWidgetSelector.draggableWidget(data.widgetName) + ).verifyVisibleElement("have.text", "Production environment testing"); }); }); diff --git a/cypress-tests/cypress/support/utils/dataSource.js b/cypress-tests/cypress/support/utils/dataSource.js index 29939455c2..8ba7a51019 100644 --- a/cypress-tests/cypress/support/utils/dataSource.js +++ b/cypress-tests/cypress/support/utils/dataSource.js @@ -7,7 +7,6 @@ import { dataSourceSelector } from "Selectors/dataSource"; import { dataSourceText } from "Texts/dataSource"; import { navigateToAppEditor } from "Support/utils/common"; - export const verifyCouldnotConnectWithAlert = (dangerText) => { cy.get(postgreSqlSelector.connectionFailedText, { timeout: 10000, @@ -133,7 +132,6 @@ export const addQueryAndOpenEditor = (queryName, query, dbName, appName) => { }); }; - export const verifyValueOnInspector = (queryName, value) => { cy.get('[data-cy="inspector-node-queries"]') .parent() @@ -157,6 +155,40 @@ export const verifyValueOnInspector = (queryName, value) => { export const selectDatasource = (datasourceName) => { cy.get(dataSourceSelector.addedDsSearchIcon).click(); cy.clearAndType(dataSourceSelector.AddedDsSearchBar, datasourceName); - cy.wait(500) - cy.get(`[data-cy="${cyParamName(datasourceName)}-button"]`).click() -} \ No newline at end of file + cy.wait(500); + cy.get(`[data-cy="${cyParamName(datasourceName)}-button"]`).click(); +}; + +export const createDataQuery = (versionId, url, key, value) => { + cy.getCookie("tj_auth_token").then((cookie) => { + const headers = { + "Tj-Workspace-Id": Cypress.env("workspaceId"), + Cookie: `tj_auth_token=${cookie.value}`, + }; + cy.request({ + method: "POST", + url: "http://localhost:3000/api/data_queries", + headers: headers, + body: { + app_id: Cypress.env("appId"), + app_version_id: versionId, + name: "restapi1", + kind: "restapi", + options: { + method: "get", + url: `{{constants.${url}}}`, + url_params: [["", ""]], + headers: [[`{{constants.${key}}}`, `{{constants.${value}}}`]], + body: [["", ""]], + json_body: null, + body_toggle: false, + transformationLanguage: "javascript", + enableTransformation: false, + }, + data_source_id: null, + }, + }).then((response) => { + expect(response.status).to.equal(201); + }); + }); +}; diff --git a/cypress-tests/cypress/support/utils/workspaceConstants.js b/cypress-tests/cypress/support/utils/workspaceConstants.js index 5e874b016a..3634c91908 100644 --- a/cypress-tests/cypress/support/utils/workspaceConstants.js +++ b/cypress-tests/cypress/support/utils/workspaceConstants.js @@ -7,13 +7,17 @@ import * as common from "Support/utils/common"; export const contantsNameValidation = (value, error) => { cy.clearAndType(commonSelectors.nameInputField, value); - cy.get(commonSelectors.nameErrorText).verifyVisibleElement("have.text", error) + cy.get(commonSelectors.nameErrorText).verifyVisibleElement( + "have.text", + error + ); cy.get(workspaceConstantsSelectors.addConstantButton).should("be.disabled"); -} +}; export const AddNewconstants = (name, value) => { cy.get(workspaceConstantsSelectors.addNewConstantButton).click(); cy.clearAndType(commonSelectors.nameInputField, name); + cy.get(commonSelectors.valueInputField).click(); cy.clearAndType(commonSelectors.valueInputField, value); cy.get(workspaceConstantsSelectors.addConstantButton).click(); -} \ No newline at end of file +}; diff --git a/frontend/src/Editor/CodeBuilder/CodeHinter.jsx b/frontend/src/Editor/CodeBuilder/CodeHinter.jsx index b3d0d4c7d2..c0fc187185 100644 --- a/frontend/src/Editor/CodeBuilder/CodeHinter.jsx +++ b/frontend/src/Editor/CodeBuilder/CodeHinter.jsx @@ -103,6 +103,8 @@ export function CodeHinter({ }) { const context = useContext(CodeHinterContext); + const hiddenWorkspaceConstantText = 'Workspace constant values are hidden'; + const darkMode = localStorage.getItem('darkMode') === 'true'; const options = { lineNumbers: lineNumbers ?? false, @@ -116,6 +118,7 @@ export function CodeHinter({ placeholder, }; const currentState = useCurrentState(); + const definedConstants = currentState?.constants; const [realState, setRealState] = useState({ ...currentState, ..._currentState, ...context }); const [currentValue, setCurrentValue] = useState(''); @@ -134,6 +137,10 @@ export function CodeHinter({ const isWorkspaceVariable = typeof currentValue === 'string' && (currentValue.includes('%%client') || currentValue.includes('%%server')); + const isWorkspaceConstant = typeof currentValue === 'string' && currentValue.includes('constants.'); + + const constantRegex = /{{constants\.([a-zA-Z0-9_]+)}}/g; + const slideInStyles = useSpring({ config: { ...config.stiff }, from: { opacity: 0, height: 0 }, @@ -180,10 +187,32 @@ export function CodeHinter({ const getPreviewAndErrorFromValue = (value) => { const customResolvables = getCustomResolvables(); + const invalidConstants = verifyConstant(value); + if (invalidConstants?.length) { + return [value, `undefined constants: ${invalidConstants}`]; + } const [preview, error] = resolveReferences(value, realState, null, customResolvables, true, true); return [preview, error]; }; + const verifyConstant = (value) => { + if (typeof value !== 'string') { + return []; + } + const matches = value.match(constantRegex); + if (!matches) { + return []; + } + const resolvedMatches = matches.map((match) => { + const cleanedMatch = match.replace(/{{constants\./, '').replace(/}}/, ''); + return Object.keys(definedConstants).includes(cleanedMatch) ? null : cleanedMatch; + }); + const invalidConstants = resolvedMatches?.filter((item) => item != null); + if (invalidConstants?.length) { + return invalidConstants; + } + }; + useEffect(() => { setCurrentValue(initialValue); const [preview, error] = getPreviewAndErrorFromValue(initialValue); @@ -240,7 +269,7 @@ export function CodeHinter({ globalPreviewCopy = preview; globalErrorCopy = null; setResolvingError(null); - setResolvedValue(preview); + setResolvedValue(isWorkspaceConstant ? hiddenWorkspaceConstantText : preview); } return [globalPreviewCopy, globalErrorCopy]; @@ -252,7 +281,7 @@ export function CodeHinter({ return () => { if (enablePreview) { setPrevCurrentValue(null); - setResolvedValue(globalPreviewCopy); + setResolvedValue(isWorkspaceConstant ? hiddenWorkspaceConstantText : globalPreviewCopy); setResolvingError(globalErrorCopy); } }; @@ -348,9 +377,9 @@ export function CodeHinter({