ToolJet/cypress-tests/cypress/support/utils/platform/multiEnv.js
Rohan Lahori 5bec5a5b12
Feature/draft versioning support (#14284)
* added app_versions fields

* added data migration for backward compatibility

* added ce specific logic

* fixed ce migration (need to dev-test)

* moved to data migration

* migration changes

* added endpoint to create draft version

* backend changes

* added draft to app_import scenario

* added version description

* minor changes (needs improvement)

* fixed breaking dropdown in editor

* updated submodule commits

* revert package.json

* revert ui not used changes

* submodule changes

* reverting non used files

* ui changes

* ui changes

* ui changes

* ui changes

* ui changes

* copywriting changes

* ui changes

* ui changes

* edit version modal changes

* ui integration changes

* added button solid and removed unused css

* removed commented code from create version modal

* updated button size to use large

* ui changes

* draft version modal changes

* added sub-module commits to main

* draft version endpoint changes

* ui changes for draft version modal

* fix breaking ui

* ui changes for banner

* minor ui changes

* remove scss changes from themes file

* removed unused components (cleanup)

* removed unused components (pr cleanup)

* draft version changes

* create version modal changes

* canvas banner fixes

* comment creation logic

* refactor: version dropdown

* update endpoint changes

* fix: promote logic

* update submodule

* fix: released version and create version modal

* fix draft version creation

* minor ui changes

* minor backend fixes

* tooltip changes

* added all components in same folder

* added minor comments

* import fixes

* refactor files

* fix: overlay issues

* fix: on version creation

* fix ce bugs

* bug fixes

* bug fixes

* bug fixes

* bug fixes

* base merge

* feat: draft versioning support with UI enhancements and backend adjustments

- Updated AppCanvas to conditionally render AppCanvasBanner based on edit mode.
- Enhanced CreateDraftVersionModal to handle version selection and creation logic.
- Modified CreateVersionModal to streamline version creation process and handle commits.
- Improved ReleaseConfirmation to include development versions in release context.
- Refactored CreateDraftButton and VersionDropdownItem for better UI consistency and dark mode support.
- Updated VersionManagerDropdown to manage draft versions and improve version selection logic.
- Enhanced version switcher and promote/release buttons with dark mode styling.
- Adjusted server-side features and constants to support new draft versioning capabilities.
- Updated styles across components for better visual consistency and responsiveness.

* minor fixes

* rebase

* merge base

* update submodule

* Add data-cy attribute for draft version components

* Update cypress test cases for draft version feature

* Update failing test cases

* Update draft version test cases

* Skip older flow

* migration changes

* migration fixes

* Update the failed test cases

* removed multiple api calls

* fix: version set on draft creation

* fixes

* fix: version update on save version

* fixes

* name fix

* fix version lock banner styling

* bump version to 3.20.50-lts across all components

---------

Co-authored-by: Vijaykant Yadav <[email protected]>
Co-authored-by: ajith-k-v <[email protected]>
Co-authored-by: gsmithun4 <[email protected]>
2025-12-05 22:13:00 +05:30

348 lines
11 KiB
JavaScript

import { Environments, WidgetPositions } from "Constants/constants/multiEnv";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { commonEeSelectors, multiEnvSelector, versionModalSelector } from "Selectors/eeCommon";
import { appVersionSelectors } from "Selectors/exportImport";
import { appEditorSelector } from "Selectors/multiEnv";
import { appVersionText } from "Texts/exportImport";
export const promoteApp = () => {
cy.get(commonEeSelectors.promoteButton).click();
cy.get(commonEeSelectors.promoteButton).eq(1).click();
cy.waitForAppLoad();
cy.wait(3000);
};
export const releaseApp = () => {
cy.get(multiEnvSelector.environmentsTag("production")).click();
cy.get(commonSelectors.releaseButton).click();
cy.get(commonSelectors.yesButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, "Version v1 released");
cy.wait(500);
};
export const launchApp = () => {
cy.url().then((url) => {
const parts = url.split("/");
const value = parts[parts.length - 1];
cy.visit(`/applications/${value}`);
cy.wait(3000);
});
};
export const createVersionFromDraft = (version) => {
cy.get(multiEnvSelector.environmentsTag("development")).click();
cy.get(versionModalSelector.saveVersionButton(version)).click();
cy.get(versionModalSelector.createVersionModal.saveButton).click();
cy.get(versionModalSelector.versionLockInfoText, { timeout: 10000 }).verifyVisibleElement(
"have.text",
"This version is locked. To make edits, create a draft version."
);
};
export const appPromote = (fromEnv, toEnv) => {
const commonActions = () => {
cy.get(multiEnvSelector.environmentsTag(fromEnv)).click();
cy.waitForElement(commonEeSelectors.promoteVersionButton);
cy.wait(200);
cy.get(commonEeSelectors.promoteVersionButton, { timeout: 10000 }).click();
cy.get(commonEeSelectors.promoteButton, { timeout: 10000 }).click();
cy.waitForAppLoad();
cy.wait(2000);
};
const transitions = {
[Environments.development]: {
[Environments.staging]: commonActions,
[Environments.production]: () => {
commonActions();
appPromote("staging", "production");
},
release: () => {
commonActions();
commonActions();
cy.get(commonSelectors.releaseButton).click();
cy.get(commonSelectors.yesButton).click();
cy.wait(500);
},
},
staging: {
production: commonActions,
release: () => {
commonActions();
cy.get(commonSelectors.releaseButton).click();
cy.get(commonSelectors.yesButton).click();
cy.wait(500);
},
},
};
const transition = transitions[fromEnv]?.[toEnv];
transition();
};
export const createNewVersion = (value, newVersion = [], version) => {
cy.get('[data-cy="list-current-env-name"]').click();
cy.get(appEditorSelector.editor.pages.envNameList).eq(0).click();
cy.get(appVersionSelectors.currentVersionField(value)).click();
cy.get(appVersionSelectors.createNewVersionButton).click();
cy.get(appVersionSelectors.createVersionInputField).click();
cy.contains(`[id*="react-select-"]`, version).click();
cy.get(appVersionSelectors.versionNameInputField).click().type(newVersion[0]);
cy.get(appVersionSelectors.createNewVersionButton).click();
cy.waitForAppLoad();
cy.verifyToastMessage(
commonSelectors.toastMessage,
appVersionText.createdToastMessage
);
cy.get(appVersionSelectors.currentVersionField(newVersion[0])).should(
"be.visible"
);
};
export const selectVersion = (value, newVersion = []) => {
cy.get(appVersionSelectors.currentVersionField(value)).click();
cy.get(".react-select__menu-list .app-version-name")
.contains(newVersion[0])
.click();
cy.waitForAppLoad();
};
export const selectEnv = (envName) => {
const envIndex = {
development: 0,
staging: 1,
production: 2,
}[envName];
const isValidEnvName = (envName) =>
envName === "development" ||
envName === "staging" ||
envName === "production";
if (isValidEnvName(envName)) {
cy.wait(1000);
cy.waitForElement('[data-cy="list-current-env-name"]');
cy.get('[data-cy="list-current-env-name"]').click();
cy.wait(500);
const envSelector = `${appEditorSelector.editor.pages.envNameList}:eq(${envIndex})`;
cy.get(envSelector).click();
cy.waitForAppLoad();
}
};
export const setupPostgreSQLDataSource = (
dsName,
secretConstantName,
dbNameConstant
) => {
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
dsName,
"postgresql",
[
{ key: "connection_type", value: "manual", encrypted: false },
{
key: "host",
value: `{{secrets.${secretConstantName}}}`,
encrypted: false,
},
{ key: "port", value: 5432, encrypted: false },
{ key: "ssl_enabled", value: false, encrypted: false },
{
key: "database",
value: `{{constants.${dbNameConstant}}}`,
encrypted: false,
},
{ key: "ssl_certificate", value: "none", encrypted: false },
{ key: "username", value: Cypress.env("pg_user"), encrypted: false },
{ key: "password", value: Cypress.env("pg_password"), encrypted: false },
{ key: "ca_cert", value: null, encrypted: true },
{ key: "client_key", value: null, encrypted: true },
{ key: "client_cert", value: null, encrypted: true },
{ key: "root_cert", value: null, encrypted: true },
{ key: "connection_string", value: null, encrypted: true },
]
);
};
export const createAppWithComponents = (
appName,
dsName,
dbNameConstant,
tableNameConstant,
globalConstantName
) => {
return cy.apiCreateApp(appName).then(() => {
cy.apiAddQueryToApp({
queryName: "psql",
options: {
mode: "sql",
transformationLanguage: "javascript",
enableTransformation: false,
query: `SELECT * FROM {{constants.${tableNameConstant}}} WHERE constant = '{{constants.${globalConstantName}}}';`,
runOnPageLoad: true,
},
dataSourceName: dsName,
dsKind: "postgresql",
});
cy.apiAddComponentToApp(
appName,
"constant_data",
WidgetPositions.constantData,
"Text",
`{{constants.${dbNameConstant}}}`
);
cy.apiAddComponentToApp(
appName,
"query_data",
WidgetPositions.queryData,
"Text",
`{{JSON.stringify(queries.psql.data)}}`
);
});
};
export const verifyEnvironmentData = (expectedDbValue, expectedQueryValue) => {
cy.get(commonWidgetSelector.draggableWidget("constant_data"))
.should("be.visible")
.should("contain.text", expectedDbValue);
cy.get(commonWidgetSelector.draggableWidget("query_data")).should(
"contain.text",
expectedQueryValue
);
};
export const selectEnvironment = (envName) => {
cy.get(multiEnvSelector.previewSettings).click({ timeout: 10000 });
cy.forceClickOnCanvas();
cy.wait(1000);
cy.get(multiEnvSelector.previewSettings).click({ timeout: 10000 });
cy.get(multiEnvSelector.envContainer).click({ timeout: 10000 });
cy.get(multiEnvSelector.envNameList)
.contains(envName)
.click({ timeout: 10000 });
};
export const releaseAndVisitApp = (appSlug) => {
cy.get(multiEnvSelector.environmentsTag("production")).click();
cy.get(commonSelectors.releaseButton).click();
cy.get(commonSelectors.yesButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, "Version v1 released");
cy.get(commonWidgetSelector.shareAppButton).click();
cy.get(commonWidgetSelector.makePublicAppToggle).check();
cy.clearAndType(commonWidgetSelector.appNameSlugInput, appSlug);
cy.get(commonSelectors.appSlugAccept)
.should("be.visible")
.and("have.text", "Slug accepted!");
cy.apiLogout();
cy.visitSlug({
actualUrl: `${Cypress.config("baseUrl")}/applications/${appSlug}`,
});
};
export const verifyQueryEditorDisabled = () => {
cy.get(appEditorSelector.editor.queryDetailsContainer).should(
"have.class",
"disabled"
);
};
export const verifyGlobalSettingsDisabled = () => {
cy.get(versionModalSelector.versionLockInfoText, { timeout: 10000 }).verifyVisibleElement(
"have.text",
"This version is locked. To make edits, create a draft version."
);
cy.get(appEditorSelector.settings.settingsSidebarIcon).click({ force: true });
cy.get(appEditorSelector.settings.maintenanceToggle)
.parents(".disabled")
.should("exist");
cy.get(appEditorSelector.settings.maxCanvasWidthInput)
.parents(".disabled")
.should("exist");
cy.get(appEditorSelector.settings.appSlugInput).should("not.be.disabled");
};
export const verifyInspectorMenuHasNoDeleteOption = () => {
cy.get(appEditorSelector.editor.inspector.buttonAria).click({
timeout: 1000,
});
cy.get(appEditorSelector.editor.inspector.componentsNode)
.should("be.visible")
.click({ timeout: 1000 });
cy.get(appEditorSelector.editor.inspector.componentsNode)
.eq(2)
.should("be.visible")
.click({ timeout: 1000 });
cy.get(appEditorSelector.editor.inspector.menuIcon).click({ force: true });
cy.get(appEditorSelector.editor.inspector.popoverBody).should("be.visible");
cy.notVisible(appEditorSelector.editor.inspector.anyDeleteInPopover);
cy.get(appEditorSelector.editor.inspector.popoverBody).should(
"not.contain.text",
"Delete"
);
cy.forceClickOnCanvas();
};
export const verifyComponentsManagerDisabled = () => {
//cy.get(".widgets-list").should("have.css", "pointer-events", "none");
cy.get(appEditorSelector.editor.components.componentsPlusButton).click();
};
export const verifyPageSettingsDisabled = () => {
cy.get(appEditorSelector.editor.pages.pagesTabButton).click();
cy.get(versionModalSelector.versionLockInfoText).verifyVisibleElement(
"have.text",
"This version is locked. To make edits, create a draft version."
);
cy.get("#page-settings-tabpane-properties .disabled", {
timeout: 8000,
}).should("exist");
cy.get("#page-settings-tabpane-styles .disabled").should("exist");
cy.forceClickOnCanvas();
};
export const verifyComponentInspectorDisabled = () => {
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.wait(500);
cy.get(versionModalSelector.versionLockInfoText).verifyVisibleElement(
"have.text",
"This version is locked. To make edits, create a draft version."
);
cy.get("#inspector-tabpane-properties .disabled").should("exist");
cy.get("#inspector-tabpane-styles .disabled").should("exist");
cy.forceClickOnCanvas();
};
export const setupWorkspaceConstant = (
constantName,
values,
tag = "Global"
) => {
const getValue = (env) => values[env] || values;
cy.apiCreateWorkspaceConstant(
constantName,
getValue(Environments.development),
[tag],
[Environments.development]
).then((res) => {
const constantId = res.body.constant.id;
cy.apiUpdateWsConstant(
constantId,
getValue(Environments.staging),
Environments.staging
);
cy.apiUpdateWsConstant(
constantId,
getValue(Environments.production),
Environments.production
);
});
};