ToolJet/cypress-tests/cypress/support/utils/apps.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

181 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { commonWidgetSelector } from "Selectors/common";
import { appPromote } from "Support/utils/platform/multiEnv";
const slugValidations = [
{ input: "", error: "App slug can't be empty" },
{ input: "_2#", error: "Special characters are not accepted." },
{ input: "t ", error: "Cannot contain spaces" },
{ input: "T", error: "Only lowercase letters are accepted." },
];
export const verifySlugValidations = (inputSelector) => {
slugValidations.forEach(({ input, error }) => {
cy.get(inputSelector).clear();
if (input) cy.clearAndType(inputSelector, input);
cy.wait(500);
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
"have.text",
error
);
});
};
export const verifySuccessfulSlugUpdate = (workspaceId, slug) => {
const host = resolveHost();
cy.get('[data-cy="app-slug-accepted-label"]').verifyVisibleElement(
"have.text",
"Slug accepted!"
);
cy.wait(500);
// cy.get(commonWidgetSelector.appLinkSucessLabel).should('be.visible');
cy.get(commonWidgetSelector.appLinkSucessLabel).should(
"have.text",
"Link updated successfully!"
);
cy.get(commonWidgetSelector.appLinkField).verifyVisibleElement(
"have.text",
`${host}/${workspaceId}/apps/${slug}`
);
};
export const verifyURLs = (workspaceId, slug, page) => {
const baseUrl = Cypress.config("baseUrl");
cy.url().should(
"eq",
page
? `${baseUrl}/${workspaceId}/apps/${slug}/home`
: `${baseUrl}/${workspaceId}/apps/${slug}`
);
cy.openInCurrentTab(commonWidgetSelector.previewButton);
cy.ifEnv("Community", () => {
cy.url().should("eq", `${baseUrl}/applications/${slug}/home?version=v1`);
});
cy.ifEnv("Enterprise", () => {
cy.url().should(
"eq",
`${baseUrl}/applications/${slug}/home?env=production&version=v1`
);
});
cy.visit("/my-workspace");
cy.visitSlug({
actualUrl: `${baseUrl}/applications/${slug}`,
});
cy.url().should("eq", `${baseUrl}/applications/${slug}`);
};
export const setUpSlug = (slug) => {
cy.get(commonWidgetSelector.shareAppButton).click();
cy.clearAndType(commonWidgetSelector.appNameSlugInput, slug);
cy.get('[data-cy="app-slug-accepted-label"]')
.should("be.visible")
.and("have.text", "Slug accepted!");
cy.get(commonWidgetSelector.modalCloseButton).click();
};
export const setupAppWithSlug = (
appName,
slug,
appType = "private",
makePublic = false
) => {
const defaultLayout = {
desktop: { top: 90, left: 9, width: 6, height: 40 },
mobile: { top: 90, left: 9, width: 6, height: 40 },
};
cy.apiCreateApp(appName);
cy.apiAddComponentToApp(appName, appType, defaultLayout, "Text", appType);
cy.ifEnv("Enterprise", () => {
cy.openApp(
"",
Cypress.env("workspaceId"),
Cypress.env("appId"),
commonWidgetSelector.draggableWidget(appType)
);
cy.apiPublishDraftVersion("v1");
appPromote("development", "production");
});
cy.wait(2000);
cy.apiReleaseApp(appName);
cy.apiAddAppSlug(appName, slug);
if (makePublic === true) {
cy.apiMakeAppPublic();
}
cy.log(`App ${appName} with slug ${slug} is set up successfully.`);
cy.log(`App ID: ${Cypress.env("appId")}`);
};
export const verifyRestrictedAccess = () => {
cy.get('[data-cy="modal-header"]').should("have.text", "Restricted access");
cy.get('[data-cy="modal-description"]')
.invoke("text")
.then((text) => {
const normalizedText = text.replace(//g, "'");
expect(normalizedText).to.equal(
"You don't have access to this app. Kindly contact admin to know more."
);
});
cy.get('[data-cy="back-to-home-button"]').verifyVisibleElement(
"have.text",
"Back to home page"
);
};
export const onboardUserFromAppLink = (
email,
slug,
workspaceName = "My workspace",
isNonExistingUser = true
) => {
const dbConfig = Cypress.env("app_db");
const query = isNonExistingUser
? `
SELECT u.invitation_token, o.id AS workspace_id, ou.invitation_token AS organization_token
FROM users u
JOIN organization_users ou ON u.id = ou.user_id
JOIN organizations o ON ou.organization_id = o.id
WHERE u.email = '${email}' AND o.name = '${workspaceName}';
`
: `
SELECT ou.invitation_token, o.id AS workspace_id
FROM users u
JOIN organization_users ou ON u.id = ou.user_id
JOIN organizations o ON ou.organization_id = o.id
WHERE u.email = '${email}' AND o.name = '${workspaceName}';
`;
cy.task("dbConnection", { dbconfig: dbConfig, sql: query }).then((resp) => {
if (!resp.rows || resp.rows.length === 0) {
throw new Error(
`No records found for email: ${email} and workspace: ${workspaceName}`
);
}
const { invitation_token, workspace_id, organization_token } = resp.rows[0];
const token = isNonExistingUser ? organization_token : invitation_token;
const url = isNonExistingUser
? `${Cypress.config("baseUrl")}/invitations/${invitation_token}/workspaces/${organization_token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`
: `${Cypress.config("baseUrl")}/organization-invitations/${token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`;
cy.visit(url);
});
};
export const resolveHost = () => {
const baseUrl = Cypress.config("baseUrl");
const urlMapping = {
"http://localhost:8082": "http://localhost:8082",
"http://localhost:3000": "http://localhost:3000",
"http://localhost:3000/apps": "http://localhost:3000/apps",
"http://localhost:4001": "http://localhost:3000",
"http://localhost:4001/apps": "http://localhost:3000/apps",
};
return urlMapping[baseUrl];
};