Merge pull request #6418 from ToolJet/release/2.6.0

Release/2.6.0
This commit is contained in:
Sherfin Shamsudeen 2023-05-23 15:54:27 +05:30 committed by GitHub
commit 5ba5339a38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
611 changed files with 61851 additions and 5035 deletions

View file

@ -33,11 +33,12 @@ jobs:
sleep 1
done
- name: Getting cypress secrets
# use quotes around the secret, as its value
# is simply inserted as a string into the command
run: |
echo '${{ secrets.CYPRESS_SECRETS }}' > cypress.env.json
- name: create-json
id: create-json
uses: jsdaniell/create-json@v1.2.2
with:
name: "cypress.env.json"
json: ${{ secrets.CYPRESS_SECRETS }}
- name: Cypress integration test
uses: cypress-io/github-action@v5
@ -45,6 +46,7 @@ jobs:
working-directory: ./cypress-tests
config: "baseUrl=https://tooljet-pr-${{ env.PR_NUMBER }}.onrender.com"
config-file: cypress-run.config.js
env: ${{ secrets.CYPRESS_SECRETS }}
- name: Capturing screenshots
uses: actions/upload-artifact@v3
@ -52,3 +54,10 @@ jobs:
with:
name: screenshots
path: cypress-tests/cypress/screenshots
- name: Capturing downloads
uses: actions/upload-artifact@v3
if: always()
with:
name: screenshots
path: cypress-tests/cypress/downloads

39
.github/workflows/doc-release.yml vendored Normal file
View file

@ -0,0 +1,39 @@
name: Documentation version release
on:
workflow_dispatch:
inputs:
create-branch:
description: "Branch name"
version:
description: "RELEASE_VERSION"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node 16.14
uses: actions/setup-node@v2
with:
node-version: 16.14
- run: cd docs && yarn install && npm run docusaurus docs:version ${{ github.event.inputs.version }}
- name: Create Pull Request
id: doc
uses: peter-evans/create-pull-request@v5
with:
title: "Creating a new version folder ${{ github.event.version }}"
body: "Created a new version folder for version: ${{ github.event.inputs.version }}"
branch: ${{ github.event.inputs.create-branch }}
base: "develop"
token: ${{ secrets.GITHUB }}
delete-branch : true
labels: versioned-docs, automated pr
commit-message: added new version folder

View file

@ -144,7 +144,7 @@ jobs:
"port": 80,
"protocol": "TCP"
}],
"plan": "starter",
"plan": "pro",
"pullRequestPreviewsEnabled": "no",
"region": "oregon",
"url": "https://tooljet-pr-${{ env.PR_NUMBER }}.onrender.com"

View file

@ -1 +1 @@
2.5.0
2.6.0

View file

@ -13,7 +13,7 @@ module.exports = defineConfig({
requestTimeout: 10000,
pageLoadTimeout: 20000,
responseTimeout: 10000,
viewportWidth: 1200,
viewportWidth: 1440,
viewportHeight: 960,
chromeWebSecurity: false,
trashAssetsBeforeRuns: true,
@ -62,7 +62,7 @@ module.exports = defineConfig({
});
on("task", {
UpdateId({ dbconfig, sql }) {
updateId({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},
@ -76,6 +76,10 @@ module.exports = defineConfig({
experimentalRunAllSpecs: true,
baseUrl: "http://localhost:8082",
specPattern: [
"cypress/e2e/selfHost/*.cy.js",
// "cypress/e2e/authentication/*.cy.js",
// "cypress/e2e/workspace/*.cy.js",
// "cypress/e2e/editor/data-source/*.cy.js",
"cypress/e2e/editor/app-version/version.cy.js",
"cypress/e2e/exportImport/export.cy.js",
"cypress/e2e/exportImport/import.cy.js",
@ -84,10 +88,14 @@ module.exports = defineConfig({
"cypress/e2e/editor/multipage/*.cy.js",
],
numTestsKeptInMemory: 1,
redirectionLimit: 10,
redirectionLimit: 7,
experimentalRunAllSpecs: true,
experimentalMemoryManagement: true,
video: false,
videoUploadOnPasses: false,
retries: {
runMode: 2,
openMode: 0,
},
},
});

View file

@ -77,10 +77,7 @@ module.exports = defineConfig({
experimentalModfyObstructiveThirdPartyCode: true,
experimentalRunAllSpecs: true,
baseUrl: "http://localhost:8082",
specPattern: [
"cypress/e2e/editor/widget/*.cy.js",
"cypress/e2e/multipage/*.cy.js",
],
specPattern: "cypress/e2e/**/*.cy.js",
downloadsFolder: "cypress/downloads",
numTestsKeptInMemory: 25,
redirectionLimit: 10,

View file

@ -34,8 +34,6 @@ export const commonSelectors = {
appNameInput: "[data-cy=app-name-input]",
launchButton: "[data-cy=launch-button]",
folderNameInput: "[data-cy=folder-name-input]",
deleteFolderOption: "[data-cy=delete-folder-card-option]",
editFolderOption: "[data-cy=edit-folder-card-option]",
deleteAppOption: "[data-cy=delete-app-card-option]",
cancelButton: "[data-cy=cancel-button]",
modalComponent: "[data-cy=modal-component]",
@ -43,7 +41,7 @@ export const commonSelectors = {
createNewFolderButton: "[data-cy=create-new-folder-button]",
folderNameInput: "[data-cy=folder-name-input]",
createFolderButton: "[data-cy=create-folder-button]",
folderList: ".css-169zxdi-MenuList",
folderList: ".react-select__menu-list",
empytyFolderImage: "[data-cy=empty-folder-image]",
emptyFolderText: "[data-cy=empty-folder-text]",
allApplicationsLink: "[data-cy=all-applications-link]",
@ -158,7 +156,7 @@ export const commonSelectors = {
resetPasswordButton: '[data-cy="reset-password-button"]',
resetPasswordPageDescription: '[data-cy="reset-password-page-description"]',
backToLoginButton: '[data-cy="back-to-login-button"]',
breadcrumbTitle: '[data-cy="breadcrumb-title"]',
breadcrumbTitle: '[data-cy="app-header-label"]>>',
breadcrumbPageTitle: '[data-cy="breadcrumb-page-title"]',
labelFullNameInput: '[data-cy="label-full-name-input-field"]',
inputFieldFullName: '[data-cy="input-field-full-name"]',
@ -166,6 +164,8 @@ export const commonSelectors = {
inputFieldEmailAddress: '[data-cy="input-field-email"]',
closeButton: '[data-cy="close-button"]',
emptyAppCreateButton: "[data-cy='button-new-app-from-scratch']",
globalDataSourceIcon: '[data-cy="icon-global-datasources"]',
addNewDataSourceButton: '[data-cy="add-new-data-source-button"]',
onboardingRadioButton: (radioButtonText) => {
return `[data-cy="${cyParamName(radioButtonText)}-radio-button"]`;
@ -202,10 +202,15 @@ export const commonSelectors = {
return `[data-cy="${cyParamName(buttonText)}-button"]`;
},
folderCardOptions: (folderName)=>{
return `[data-cy="${cyParamName(folderName)}-list-card"]>[data-cy="folder-card-menu-icon"]>svg`
folderCardOptions: (folderName) => {
return `[data-cy="${cyParamName(folderName)}-card-menu-icon"]`;
},
deleteFolderOption: (folderName) => {
return `[data-cy="${cyParamName(folderName)}-delete-folder-option"]`;
},
editFolderOption: (folderName) => {
return `[data-cy="${cyParamName(folderName)}-edit-folder-option"]`;
},
};
export const commonWidgetSelector = {

View file

@ -22,16 +22,16 @@ export const dashboardSelector = {
changeButton: "[data-cy=change-button]",
addToFolderTitle: "[data-cy=add-to-folder-title]",
moveAppText: "[data-cy=move-selected-app-to-text]",
selectFolder: '[data-cy="select-folder"]>>>>.css-h380uj-Input',
selectFolder: '[data-cy="select-folder"]>.css-nwhe5y-container > .react-select__control > .react-select__value-container',
addToFolderButton: "[data-cy=add-to-folder-button]",
appTemplateRow: '[data-cy="app-template-row"]',
homePageContent: '[data-cy="home-page-content"]',
seeAllAppsTemplateButton: '[data-cy="see-all-app-template-buton"]',
folderLabel: '[data-cy="folder-info"]',
dashboardAppsHeaderLabel:'[data-cy="app-header-label"]',
dashboardAppsHeaderLabel: '[data-cy="app-header-label"]',
versionLabel: '[data-cy="version-label"]',
dashboardAppCreateButton: '[data-cy="button-new-app-from-scratch"]',
appCardIcon: (iconName) => {
return `[data-cy="app-card-${cyParamName(iconName)}-icon"]`;
},

View file

@ -6,7 +6,7 @@ export const groupsSelector = {
createNewGroupButton: "[data-cy=create-new-group-button]",
tableHeader: "[data-cy=table-header]",
groupName: "[data-cy=group-name]",
cardTitle: "[data-cy=card-title]",
addNewGroupModalTitle: '[data-cy="add-new-group-title"]',
groupNameInput: "[data-cy=group-name-input]",
cancelButton: "[data-cy=cancel-button]",
createGroupButton: "[data-cy=create-group-button]",
@ -15,8 +15,7 @@ export const groupsSelector = {
usersLink: "[data-cy=users-link]",
permissionsLink: "[data-cy=permissions-link]",
searchBox: '[data-cy="select-search"]',
appSearchBox:
"[data-cy=select-search]>>>>>.dropdown-heading-value > .gray",
appSearchBox: "[data-cy=select-search]>>>>>.dropdown-heading-value > .gray",
searchBoxOptions: ".panel-content",
appAddButton: "[data-cy=add-button]",
addButton: '[data-cy="add-button"]',
@ -41,19 +40,28 @@ export const groupsSelector = {
multiSelectSearchInput:
'[data-cy="multi-select-search"]>>>>.select-search__input',
workspaceVarCreateLabel: '[data-cy="workspace-variable-create-label"]',
selectAddButton: '[data-cy="add-button"]',
textDefaultGroup: '[data-cy="text-default-group"]',
helperTextNoAppsAdded: '[data-cy="helper-text-no-apps-added"]',
helperTextPermissions: '[data-cy="helper-text-user-groups-permissions"]',
helperTextAllUsersIncluded: '[data-cy="helper-text-all-user-included"]',
helperTextAdminAppAccess: '[data-cy="helper-text-admin-app-access"]',
helperTextAdminPermissions: '[data-cy="helper-text-admin-permissions"]',
updateGroupNameModalTitle: '[data-cy="update-group-title"]',
groupLink: (groupname) => {
return `[data-cy="${cyParamName(groupname)}-group-link"]`;
return `[data-cy="${cyParamName(groupname)}-list-item"]`;
},
updateGroupNameLink: (groupname) => {
return `[data-cy="${cyParamName(groupname)}-group-update-link"]`;
return `[data-cy="${cyParamName(groupname)}-group-name-update-link"]`;
},
deleteGroupLink: (groupname) => {
return `[data-cy="${cyParamName(groupname)}-group-delete-link"]`;
},
mutiSelectAddButton: (groupname) => {
return `[data-cy="${cyParamName(
groupname
)}-group-multi-select-search-add-button"]`;
return `[data-cy="${cyParamName(groupname)}-group-add-button"]`;
},
groupPageTitle: (groupname) => {
return `[data-cy="${cyParamName(groupname)}-title"]`;
},
selectAddButton: '[data-cy="add-button"]'
};

View file

@ -31,7 +31,7 @@ export const ssoSelector = {
googleSSOText: "[data-cy=google-sso-text]",
git: '[data-cy="github-list-item"]',
gitEnableToggle: '[data-cy="github-toggle-input"]',
githubLabel:'[data-cy="github-toggle-label"]',
githubLabel: '[data-cy="github-toggle-label"]',
clientSecretLabel: "[data-cy=client-secret-label]",
encriptedLabel: "[data-cy=encripted-label]",
clientSecretInput: "[data-cy=client-secret-input]",
@ -52,4 +52,4 @@ export const ssoSelector = {
passwordLoginToggleLbale: '[data-cy="label-password-login"]',
alertText: '[data-cy="alert-text"]',
disablePasswordHelperText: '[data-cy="disable-password-helper-text"]',
};
};

View file

@ -4,8 +4,9 @@ export const usersSelector = {
usersElements: {
usersTableNameColumnHeader: '[data-cy="users-table-name-column-header"]',
usersTableEmailColumnHeader: '[data-cy="users-table-email-column-header"]',
usersTableStatusColumnHeader: '[data-cy="users-table-status-column-header"]',
usersFilterLabel: '[data-cy="users-filter-label"]'
usersTableStatusColumnHeader:
'[data-cy="users-table-status-column-header"]',
usersFilterLabel: '[data-cy="users-filter-label"]',
},
usersPageTitle: '[data-cy="title-users-page"]',
userFilterInput: '[data-cy="users-filter-input"]',
@ -54,8 +55,8 @@ export const usersSelector = {
buttonDownloadTemplate: '[data-cy="button-download-template"]',
buttonUploadUsers: '[data-cy="button-upload-users"]',
helperTextBulkUpload: '[data-cy="helper-text-bulk-upload"]',
iconBulkUpload:'[data-cy="icon-bulk-upload"]',
helperTextSelectFile:'[data-cy="helper-text-select-file"]',
iconBulkUpload: '[data-cy="icon-bulk-upload"]',
helperTextSelectFile: '[data-cy="helper-text-select-file"]',
helperTextDropFile: '[data-cy="helper-text-drop-file"]',
inputFieldBulkUpload: '[data-cy="input-field-bulk-upload"]',
copyInvitationLink: '[data-cy="copy-invitation-link"]',

View file

@ -3,10 +3,10 @@ export const postgreSqlSelector = {
labelDataSources: "[data-cy='label-datasources']",
addDatasourceLink: "[data-cy='add-datasource-link']",
allDatasourceLabelAndCount: '[data-rb-event-key="#alldatasources"]',
databaseLabelAndCount: '[data-rb-event-key="#databases"]',
apiLabelAndCount: '[data-rb-event-key="#apis"]',
cloudStorageLabelAndCount: '[data-rb-event-key="#cloudstorage"]',
allDatasourceLabelAndCount: '[data-rr-ui-event-key="#alldatasources"]',
databaseLabelAndCount: '[data-rr-ui-event-key="#databases"]',
apiLabelAndCount: '[data-rr-ui-event-key="#apis"]',
cloudStorageLabelAndCount: '[data-rr-ui-event-key="#cloudstorage"]',
dataSourceSearchInputField: '[data-cy="datasource-search-input"]',
postgresDataSource: "[data-cy='data-source-postgresql']",
@ -24,7 +24,7 @@ export const postgreSqlSelector = {
buttonTestConnection: '[data-cy="test-connection-button"]',
connectionFailedText: '[data-cy="test-connection-failed-text"]',
buttonSave: '[data-cy="db-connection-save-button"]',
dangerAlertNotSupportSSL: '[class="alert alert-danger"]',
dangerAlertNotSupportSSL: '.go3958317564',
passwordTextField: '[data-cy="password-text-field"]',
textConnectionVerified: '[data-cy="test-connection-verified-text"]',

View file

@ -3,7 +3,7 @@ export const profileSelector = {
profileLink: "[data-cy=profile-link]",
logoutLink: "[data-cy=logout-link]",
profileElements: {
pageTitle: "[data-cy=page-title]",
pageTitle: '[data-cy="dashboard-section-header"]',
profileCard: "[data-cy=card-title-profile]",
firstNameLabel: "[data-cy=first-name-label]",
lastNameLabel: "[data-cy=last-name-label]",

View file

@ -125,11 +125,12 @@ export const commonText = {
"Your password has been reset successfully, log into ToolJet to continue your session",
labelFullNameInput: "Enter full name",
labelEmailInput: "Email address",
breadcrumbworkspaceSettingTitle:"Workspace settings",
breadcrumbworkspaceSettingTitle: "Workspace settings",
breadcrumbGlobalDatasourceTitle: "Global datasources",
breadcrumbDatabaseTitle: "Databse",
breadcrumbApplications: "Applications",
breadcrumbSettings: "Settings",
addNewDataSourceButton: "Add new datasource",
emailPageDescription: (email) => {
return `Weve sent an email to ${email} with a verification link. Please use that to verify your email address.`;

View file

@ -2,8 +2,8 @@ export const dashboardText = {
emptyPageHeader: "Welcome to your new ToolJet workspace",
emptyPageDescription:
"You can get started by creating a new application or by creating an application using a template in ToolJet Library.",
createAppButton: "New app from scratch",
importAppButton: ' Import an application',
createAppButton: "Create new application",
importAppButton: "Import an app",
chooseFromTemplate: "Choose from template",
darkMode: "#808080",
lightMode: "#fff",
@ -19,27 +19,29 @@ export const dashboardText = {
iconUpdatedToast: "Icon updated.",
iconText: {
appsIcon: "apps",
businessIcon: "business",
calendarIcon: "calendar",
chartBarIcon: "Chart bar",
codeIcon: "Code",
cpuIcon: "cpu",
databaseIcon: "database",
fileAnalyticsIcon: "file analytics",
flameIcon: "flame",
presentationIcon: "presentation",
reportSearchIcon: "report-search",
settingsIcon: "settings",
userIcon: "users",
worldIcon: "world",
archiveIcon: "archive",
floppyIcon: "floppy",
layerIcon: "layer",
folderUpload: "folder-upload",
gridIcon: "grid",
homeIcon: "home",
sentFastIcon: "sent-fast",
serverIcon: "server",
globeIcon: "globe",
shareIcon: "share",
shieldIcon: "shield",
sunIcon: "sun",
tableIcon: "table",
menuHomeIcon: "menu-home",
dragHandleIcon: "drag-handle",
},
seeAllAppsTemplateButton: "See all templates",
addToFolderTitle: "Add to folder",
appClonedToast: "App cloned successfully.",
darkModeText: "Dark Mode",
lightModeText: "Light Mode",
dashboardAppsHeaderLabel: "Apps",
dashboardAppsHeaderLabel: " All apps",
moveAppText: (appName) => {
return `Move "${appName}" to`;
},
@ -47,5 +49,4 @@ export const dashboardText = {
folderName: (folderName) => {
return folderName;
},
};

View file

@ -22,7 +22,7 @@ export const databaseText = {
return `${tableName} created successfully`;
},
tableDeletedSuccessfullyToast: (tableName) => {
return `Table "${tableName}" deleted successfully`
return `Table "${tableName}" deleted successfully`;
},
tableEditedSuccessfullyToast: (tableName) => {
return `${tableName} edited successfully`;
@ -31,30 +31,29 @@ export const databaseText = {
return `Table name already exists: ${tableName}`;
},
deleteRowToast: (tableName, rowNumber) => {
return `Deleted ${rowNumber} rows from table "${tableName}"`
return `Deleted ${rowNumber} rows from table "${tableName}"`;
},
invalidErrorText: (value) => {
return `invalid input syntax for type integer: "${value}"`
}
return `invalid input syntax for type integer: "${value}"`;
},
};
export const createNewColumnText = {
createNewColumnHeader: "Create a new column",
columnNameLabel: 'Column name',
dataTypeLabel: 'Data type',
defaultValueLabel: 'Default value',
columnCreatedSuccessfullyToast: 'Column created successfully',
}
columnNameLabel: "Column name",
dataTypeLabel: "Data type",
defaultValueLabel: "Default value",
columnCreatedSuccessfullyToast: "Column created successfully",
};
export const createNewRowText = {
createNewRowHeader: 'Create a new row',
serialDataTypeLabel: 'SERIAL',
rowCreatedSuccessfullyToast: 'Row created successfully',
}
createNewRowHeader: "Create a new row",
serialDataTypeLabel: "SERIAL",
rowCreatedSuccessfullyToast: "Row created successfully",
};
export const filterText = {
filterText: ' Filter',
filterText: " Filter",
operation: {
equals: "equals",
greaterThan: "greater than",
@ -68,16 +67,17 @@ export const filterText = {
imatch: "imatch",
in: "in",
},
}
};
export const sortText = {
sortByText: 'Sort by',
sortByText: "Sort by",
order: {
ascending: "Ascending",
descending: "Descending"
}
}
descending: "Descending",
},
};
export const editRowText = {
editRowHeader: "Edit a row",
selectRowToEditText: "Select a row to edit"
}
selectRowToEditText: "Select a row to edit",
rowEditedSuccessfullyToast: "Row edited successfully",
};

View file

@ -12,12 +12,13 @@ export const groupsText = {
groupCreatedToast: "Group has been created",
userGroup: "User group",
appsLink: "Apps",
usersLink: "Users",
usersLink: "User",
permissionsLink: "Permissions",
addButton: "Add",
nameTableHeader: "name",
addButton: "Add apps",
addUsersButton: "Add users",
userNameTableHeader: "User name",
permissionstableHedaer: "Permissions",
emailTableHeader: "email",
emailTableHeader: "Email id",
resourcesTableHeader: "Resources",
resourcesApps: "Apps",
resourcesFolders: "Folder",
@ -30,4 +31,19 @@ export const groupsText = {
confirmCancelButton: "Cancel",
confirmYesButton: "Yes",
resourcesWorkspaceVar: "Workspace Variables",
textDefaultGroup: "Default group",
textAppName: "App name",
helperTextNoAppsAdded: "No apps are added to the group",
helperTextPermissions:
"Add app to the group to control permissions for users in this group",
helperTextAllUsersIncluded:
" All users include every users in the app. This list is not editable",
helperTextAdminAppAccess:
"Admin has edit access to all apps. These are not editable",
helperTextAdminPermissions: "Admin has all permissions",
updateGroupNameModalTitle: "Update group",
saveButton: "Save",
groupNameUpdateSucessToast: "Group name updated successfully",
editGroupNameButton: "Edit name",
deleteGroupButton: " Delete group",
};

View file

@ -49,8 +49,10 @@ export const ssoText = {
noLoginMethodWarning: "No login methods enabled for this workspace",
googleSignUpText: "Sign up with Google",
gitSignUpText: "Sign up with GitHub",
gitUserStatusToast:"GitHub login failed - User does not exist in the workspace",
passwordLoginToggleLbale: 'Password login ',
alertText: 'Danger zone',
disablePasswordHelperText: 'Disable password login only if your SSO is configured otherwise you will get logged out.',
};
gitUserStatusToast:
"GitHub login failed - User does not exist in the workspace",
passwordLoginToggleLbale: "Password login ",
alertText: "Danger zone",
disablePasswordHelperText:
"Disable password login only if your SSO is configured otherwise you will get logged out.",
};

View file

@ -3,7 +3,7 @@ export const usersText = {
usersTableNameColumnHeader: "NAME",
usersTableEmailColumnHeader: "EMAIL",
usersTableStatusColumnHeader: "STATUS",
usersFilterLabel: "Showing"
usersFilterLabel: "Showing",
},
usersPageTitle: "users",
breadcrumbUsersPageTitle: " Users & permissions",
@ -46,15 +46,16 @@ export const usersText = {
},
swPasswordSuccessToast:
"Added to the workspace and password has been set successfully.",
inviteBulkUserButton:"Invite bulk users",
inviteBulkUserButton: "Invite bulk users",
bulkUserUploadPageTitle: "Upload Users",
buttonDownloadTemplate: 'Download Template',
buttonUploadUsers:"Upload users",
buttonDownloadTemplate: "Download Template",
buttonUploadUsers: "Upload users",
buttonInviteWithEmail: " Invite with email",
buttonUploadCsvFile: "Upload CSV file",
helperTextBulkUpload: 'Download the ToolJet template to add user details or format your file in the same as the template. ToolJet wont be able to recognise files in any other format. ',
helperTextSelectFile:'Select a CSV file to upload',
helperTextDropFile: 'Or drag and drop it here',
helperTextBulkUpload:
"Download the ToolJet template to add user details or format your file in the same as the template. ToolJet wont be able to recognise files in any other format. ",
helperTextSelectFile: "Select a CSV file to upload",
helperTextDropFile: "Or drag and drop it here",
};

View file

@ -2,9 +2,9 @@ export const postgreSqlText = {
labelDataSources: "Datasources",
labelAddDataSource: "+ add data source",
allDataSources: "All Datasources (39)",
allDatabase: "Databases (17)",
allApis: "APIs (19)",
allDataSources: "All Datasources (42)",
allDatabase: "Databases (19)",
allApis: "APIs (20)",
allCloudStorage: "Cloud Storage (3)",
postgreSQL: "PostgreSQL",

View file

@ -1,7 +1,7 @@
export const profileText = {
profileLink: "Profile",
profileElements: {
pageTitle: "Profile Settings",
pageTitle: "Profile settings",
profileCard: "Profile",
firstNameLabel: "First name",
lastNameLabel: "Last name",

View file

@ -1,25 +1,32 @@
import { cyParamName } from "Selectors/common";
export const editVersionText = {
editVersionTitle: 'Edit Version',
saveButton: 'Save',
VersionNameUpdatedToastMessage: 'Version name updated'
}
editVersionTitle: "Edit Version",
saveButton: "Save",
VersionNameUpdatedToastMessage: "Version name updated",
};
export const deleteVersionText = {
deleteModalText: (text) => {
return `Are you sure you want to delete this version - ${cyParamName(text)}`;
},
deleteToastMessage: (version) => {
return `Version - ${cyParamName(version)} Deleted`
}
}
deleteModalText: (text) => {
return `Are you sure you want to delete this version - ${cyParamName(
text
)}`;
},
deleteToastMessage: (version) => {
return `Version - ${cyParamName(version)} Deleted`;
},
};
export const releasedVersionText = {
cannotUpdateReleasedVersionToastMessage: "You cannot update a released version",
releasedToastMessage: (version) => {
return `Version ${cyParamName(version)} released`
},
releasedModalText: "You cannot make changes to a version that has already been released. Create a new version or switch to a different version if you want to make changes.",
cannotDeleteReleasedVersionToastMessage: "You cannot delete a released version"
}
cannotUpdateReleasedVersionToastMessage:
"You cannot update a released version",
releasedToastMessage: (version) => {
return `Version ${cyParamName(version)} released`;
},
releasedModalText:
"You cannot make changes to a version that has already been released. Create a new version or switch to a different version if you want to make changes.",
cannotDeleteReleasedVersionToastMessage:
"You cannot delete a released version",
releasedAppText:
"This is a released app. Create a new version to make changes.",
};

View file

@ -10,7 +10,7 @@ export const workspaceVarText = {
encryptionToggleLabel: "Enable encryption",
addVariableButton: "Add variable",
workspaceVarTableNameHeader: "Name",
workspaceVarTableValueHeader:"Value",
workspaceVarTableValueHeader: "Value",
workspaceVarTableTypeHeader: "Type",
workspaceVarCreatedToast: "Variable has been created",
workspaceVarUpdatedToast: "Variable has been updated",

View file

@ -64,40 +64,44 @@ describe("Password reset functionality", () => {
cy.clearAndType(commonSelectors.emailInputField, data.email);
cy.get(commonSelectors.resetPasswordLinkButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
commonText.passwordResetEmailToast
);
cy.get(commonSelectors.pageLogo).should("be.visible");
cy.get(commonSelectors.emailImage).should("be.visible");
cy.get(commonSelectors.onboardingPageHeader).verifyVisibleElement(
"have.text",
commonText.emailPageHeader
);
cy.get(commonSelectors.onboardingPageDescription).verifyVisibleElement(
"have.text",
commonText.resetPasswordEmailDescription(data.email)
);
cy.get(commonSelectors.spamMessage).verifyVisibleElement(
"have.text",
commonText.spamMessage
);
cy.get(commonSelectors.onboardingSeperator).should("be.visible");
cy.get(commonSelectors.onboardingSeperatorText).verifyVisibleElement(
"have.text",
commonText.onboardingSeperatorText
);
cy.get(commonSelectors.backToLoginButton).verifyVisibleElement(
"have.text",
commonText.backToLoginButton
);
cy.get("body").then(($title) => {
if (!$title.text().includes("Forgot Password")) {
cy.verifyToastMessage(
commonSelectors.toastMessage,
commonText.passwordResetEmailToast
);
cy.get(commonSelectors.pageLogo).should("be.visible");
cy.get(commonSelectors.emailImage).should("be.visible");
cy.get(commonSelectors.onboardingPageHeader).verifyVisibleElement(
"have.text",
commonText.emailPageHeader
);
cy.get(commonSelectors.onboardingPageDescription).verifyVisibleElement(
"have.text",
commonText.resetPasswordEmailDescription(data.email)
);
cy.get(commonSelectors.spamMessage).verifyVisibleElement(
"have.text",
commonText.spamMessage
);
cy.get(commonSelectors.onboardingSeperator).should("be.visible");
cy.get(commonSelectors.onboardingSeperatorText).verifyVisibleElement(
"have.text",
commonText.onboardingSeperatorText
);
cy.get(commonSelectors.backToLoginButton).verifyVisibleElement(
"have.text",
commonText.backToLoginButton
);
}
});
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select forgot_password_token from users where email='${data.email}';`,
}).then((resp) => {
passwordResetLink = `http://localhost:8082/reset-password/${resp.rows[0].forgot_password_token}`;
passwordResetLink = `/reset-password/${resp.rows[0].forgot_password_token}`;
});
});

View file

@ -37,7 +37,7 @@ describe("User signup", () => {
dbconfig: Cypress.env("app_db"),
sql: `select invitation_token from users where email='${data.email}';`,
}).then((resp) => {
invitationLink = `http://localhost:8082/invitations/${resp.rows[0].invitation_token}`;
invitationLink = `/invitations/${resp.rows[0].invitation_token}`;
});
verifyConfirmEmailPage(data.email);
});
@ -45,7 +45,7 @@ describe("User signup", () => {
cy.visit(invitationLink);
verifyConfirmPageElements();
cy.get(commonSelectors.setUpToolJetButton).click();
cy.wait(500);
cy.wait(4000);
cy.get("body").then(($el) => {
if (!$el.text().includes(dashboardText.emptyPageHeader)) {
verifyOnboardingQuestions(data.fullName, data.workspaceName);

View file

@ -1,240 +0,0 @@
import { commonSelectors } from "Selectors/common";
import { fake } from "Fixtures/fake";
import { usersText } from "Texts/manageUsers";
import * as common from "Support/utils/common";
import { dashboardText, emptyDashboardText } from "Texts/dashboard";
import { groupsSelector } from "Selectors/manageGroups";
import { groupsText } from "Texts/manageGroups";
import * as permissions from "Support/utils/userPermissions";
import { usersSelector } from "Selectors/manageUsers";
import { commonText } from "Texts/common";
import { workspaceVarSelectors } from "Selectors/workspaceVariable";
import { workspaceVarText } from "Texts/workspacevarText";
const data = {};
data.firstName = fake.firstName;
data.lastName = fake.lastName.replaceAll("[^A-Za-z]", "");
data.email = fake.email.toLowerCase();
data.appName = `${fake.companyName} App`;
data.folderName = `${fake.companyName} Folder`;
data.companyName = fake.companyName;
describe("User permissions", () => {
beforeEach(() => {
cy.appUILogin();
});
it("Should verify the create new app permission", () => {
permissions.reset();
permissions.addNewUserMW(
data.firstName,
data.email
);
cy.get("body").then(($title) => {
if ($title.text().includes(dashboardText.emptyPageDescription)) {
cy.get(commonSelectors.dashboardAppCreateButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.createAppPermissionToast
);
} else {
cy.contains(dashboardText.createAppButton).should("not.exist");
}
});
common.logout();
});
it("Should verify the View and Edit permission", () => {
common.navigateToManageUsers();
common.searchUser(data.email);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get("td small").should("have.text", usersText.activeStatus);
});
cy.intercept('GET', '/api/apps?page=1&folder=&searchKey=').as('homePage');
cy.get(commonSelectors.homePageLogo).click();
cy.wait('@homePage');
cy.createApp();
cy.renameApp(data.appName);
cy.get(commonSelectors.editorPageLogo).click();
common.navigateToManageGroups();
cy.get(groupsSelector.appSearchBox).click();
cy.get(groupsSelector.searchBoxOptions).contains(data.appName).click();
cy.get(groupsSelector.selectAddButton).click();
cy.get("table").contains("td", data.appName);
cy.contains("td", data.appName)
.parent()
.within(() => {
cy.get("td input").first().should("be.checked");
});
common.logout();
cy.login(data.email, usersText.password);
cy.contains(data.appName).should("exist");
cy.get(commonSelectors.appCard(data.appName)).should(
"contain.text",
data.appName
);
cy.contains("div", data.appName)
.parent()
.within(() => {
cy.get(commonSelectors.appTitle(data.appName)).trigger("mouseover");
cy.get(commonSelectors.launchButton).should("have.class", "tj-disabled-btn");
});
permissions.adminLogin();
cy.contains("tr", data.appName)
.parent()
.within(() => {
cy.get("td input").eq(1).check();
});
common.logout();
cy.login(data.email, usersText.password);
cy.get(commonSelectors.appCard(data.appName)).should(
"contain.text",
data.appName
);
cy.contains("div", data.appName)
.parent()
.within(() => {
cy.get(commonSelectors.appTitle(data.appName)).trigger("mouseover");
});
cy.get(commonSelectors.launchButton).should("have.class", "tj-disabled-btn");
cy.get(commonSelectors.editButton).should("exist").and("be.enabled");
cy.get(commonSelectors.workspaceName).click();
cy.contains("Untitled workspace").click();
cy.contains(data.appName).should("not.exist");
cy.get(commonSelectors.workspaceName).click();
cy.contains("My workspace").should("be.visible").click();
cy.wait(200);
});
it("Should verify the Create and Delete app permission", () => {
common.navigateToManageGroups();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsCreateCheck).check();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsDeleteCheck).check();
common.logout();
cy.login(data.email, usersText.password);
cy.get(commonSelectors.appCreateButton).should("exist");
cy.get(commonSelectors.appCardOptionsButton).first().click();
cy.contains("Delete app").should("exist");
permissions.adminLogin();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsDeleteCheck).uncheck();
common.logout();
cy.login(data.email, usersText.password);
cy.get(commonSelectors.appCardOptionsButton).first().click();
cy.contains("Delete app").should("not.exist");
cy.createApp();
cy.renameApp(data.appName);
cy.get(commonSelectors.editorPageLogo).click();
cy.get(commonSelectors.appCardOptionsButton).first().click();
cy.contains("Delete app").should("exist");
cy.get(commonSelectors.appCardOptions(commonText.deleteAppOption)).click();
cy.get(commonSelectors.buttonSelector("Yes")).click();
permissions.adminLogin();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsCreateCheck).uncheck();
common.logout();
cy.login(data.email, usersText.password);
cy.contains("Create new application").should("not.exist");
});
it("Should verify Create/Update/Delete folder permission", () => {
common.navigateToManageGroups();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.foldersCreateCheck).check();
common.logout();
cy.login(data.email, usersText.password);
cy.get(commonSelectors.createNewFolderButton).click();
cy.clearAndType(commonSelectors.folderNameInput, data.folderName);
cy.get(commonSelectors.createFolderButton).click();
cy.contains(data.folderName).should("exist");
cy.contains("div", data.folderName).parent().within(()=>{
cy.get(commonSelectors.folderCardOptions).invoke("click");
})
cy.get(commonSelectors.deleteFolderOption).click();
cy.get(commonSelectors.buttonSelector("Yes")).click();
permissions.adminLogin();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.foldersCreateCheck).uncheck();
common.logout();
cy.login(data.email, usersText.password);
permissions.adminLogin();
cy.contains("td", data.appName)
.parent()
.within(() => {
cy.get("td a").contains("Remove").click();
});
common.logout();
cy.login(data.email, usersText.password);
cy.contains(data.appName).should("not.exist");
common.logout();
cy.appUILogin();
cy.deleteApp(data.appName);
});
it("Should verify Create/Update/Delete workspace variable permission", ()=>{
common.navigateToWorkspaceVariable();
cy.get(workspaceVarSelectors.addNewVariableButton).should("exist");
common.logout();
cy.login(data.email, usersText.password);
common.navigateToWorkspaceVariable();
cy.get(workspaceVarSelectors.addNewVariableButton).should("not.exist");
permissions.adminLogin();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.workspaceVarCheckbox).check();
common.logout();
cy.login(data.email, usersText.password);
common.navigateToWorkspaceVariable();
cy.get(workspaceVarSelectors.addNewVariableButton).should("exist").click();
cy.clearAndType(workspaceVarSelectors.workspaceVarNameInput, data.firstName);
cy.clearAndType(workspaceVarSelectors.workspaceVarValueInput, common.randomValue());
cy.get(workspaceVarSelectors.addVariableButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
workspaceVarText.workspaceVarCreatedToast
);
cy.get(workspaceVarSelectors.workspaceVarName(data.firstName)).should("be.visible");
cy.get(workspaceVarSelectors.workspaceVarEditButton(data.firstName)).click();
cy.clearAndType(workspaceVarSelectors.workspaceVarNameInput, data.lastName);
cy.get(workspaceVarSelectors.addVariableButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
workspaceVarText.workspaceVarUpdatedToast
);
cy.get(workspaceVarSelectors.workspaceVarName(data.lastName)).should("be.visible");
cy.get(workspaceVarSelectors.workspaceVarDeleteButton(data.lastName)).click();
cy.get(commonSelectors.buttonSelector("Yes")).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
workspaceVarText.workspaceVarDeletedToast
);
})
});

View file

@ -1,237 +0,0 @@
import { ssoSelector } from "Selectors/manageSSO";
import * as common from "Support/utils/common";
import { ssoText } from "Texts/manageSSO";
import * as SSO from "Support/utils/manageSSO";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
describe("Manage SSO for single workspace", () => {
beforeEach(() => {
cy.appUILogin();
});
it("Should verify General settings page elements", () => {
common.navigateToManageSSO();
// cy.get(ssoSelector.pagetitle).verifyVisibleElement("have.text", "SSO");
cy.get(ssoSelector.cardTitle).verifyVisibleElement(
"have.text",
ssoText.generalSettingsElements.generalSettings
);
cy.get(
ssoSelector.generalSettingsElements.generalSettings
).verifyVisibleElement(
"have.text",
ssoText.generalSettingsElements.generalSettings
);
cy.get(
ssoSelector.generalSettingsElements.enableSignupLabel
).verifyVisibleElement(
"have.text",
ssoText.generalSettingsElements.enableSignupLabel
);
cy.get(ssoSelector.generalSettingsElements.helperText).verifyVisibleElement(
"have.text",
ssoText.generalSettingsElements.helperText
);
cy.get(
ssoSelector.generalSettingsElements.allowedDomainLabel
).verifyVisibleElement(
"have.text",
ssoText.generalSettingsElements.allowedDomainLabel
);
cy.get(
ssoSelector.generalSettingsElements.allowedDomainHelperText
).verifyVisibleElement(
"have.text",
ssoText.generalSettingsElements.allowedDomainHelperText
);
cy.get(ssoSelector.enableSignUpToggle).should("be.visible");
cy.get(ssoSelector.allowedDomainInput).should("be.visible");
cy.get(ssoSelector.cancelButton).verifyVisibleElement(
"have.text",
ssoText.cancelButton
);
cy.get(ssoSelector.saveButton).verifyVisibleElement(
"have.text",
ssoText.saveButton
);
SSO.generalSettingsSW();
});
it("Should verify Google SSO page elements", () => {
common.navigateToManageSSO();
cy.get(ssoSelector.google).should("be.visible").click();
cy.get(ssoSelector.cardTitle)
.should(($el) => {
expect($el.contents().first().text().trim()).to.eq(ssoText.googleTitle);
})
.and("be.visible");
cy.get(ssoSelector.googleEnableToggle).should("be.visible");
cy.get(ssoSelector.clientIdLabel).verifyVisibleElement(
"have.text",
ssoText.clientIdLabel
);
cy.get(ssoSelector.clientIdInput).should("be.visible");
cy.get(ssoSelector.cancelButton).verifyVisibleElement(
"have.text",
ssoText.cancelButton
);
cy.get(ssoSelector.saveButton).verifyVisibleElement(
"have.text",
ssoText.saveButton
);
SSO.googleSSOPageElements();
cy.get(ssoSelector.redirectUrlLabel).verifyVisibleElement(
"have.text",
ssoText.redirectUrlLabel
);
cy.get(ssoSelector.redirectUrl).should("be.visible");
common.logout();
cy.get(ssoSelector.googleIcon).should("be.visible");
cy.get(ssoSelector.googleSSOText).verifyVisibleElement(
"have.text",
ssoText.googleSSOText
);
});
it("Should verify Git SSO page elements", () => {
common.navigateToManageSSO();
cy.get(ssoSelector.git).should("be.visible").click();
cy.get(ssoSelector.cardTitle)
.should(($el) => {
expect($el.contents().first().text().trim()).to.eq(ssoText.gitTitle);
})
.and("be.visible");
cy.get(ssoSelector.gitEnableToggle).should("be.visible");
cy.get(ssoSelector.clientIdLabel).verifyVisibleElement(
"have.text",
ssoText.clientIdLabel
);
cy.get(ssoSelector.clientIdInput).should("be.visible");
cy.get(ssoSelector.clientSecretLabel)
.should(($el) => {
expect($el.contents().first().text().trim()).to.eq(
ssoText.clientSecretLabel
);
})
.and("be.visible");
cy.get(ssoSelector.hostNameLabel).verifyVisibleElement(
"have.text",
ssoText.hostNameLabel
);
cy.get(ssoSelector.hostNameInput).should("be.visible");
cy.get(ssoSelector.hostNameHelpText).verifyVisibleElement(
"have.text",
ssoText.hostNameHelpText
);
cy.get(ssoSelector.encriptedLabel).verifyVisibleElement(
"have.text",
ssoText.encriptedLabel
);
cy.get(ssoSelector.clientSecretInput).should("be.visible");
cy.get(ssoSelector.cancelButton).verifyVisibleElement(
"have.text",
ssoText.cancelButton
);
cy.get(ssoSelector.saveButton).verifyVisibleElement(
"have.text",
ssoText.saveButton
);
SSO.gitSSOPageElements();
cy.get(ssoSelector.redirectUrlLabel).verifyVisibleElement(
"have.text",
ssoText.redirectUrlLabel
);
cy.get(ssoSelector.redirectUrl).should("be.visible");
common.logout();
cy.get(ssoSelector.gitTile).should("be.visible");
cy.get(ssoSelector.gitIcon).should("be.visible");
cy.get(ssoSelector.gitSSOText).verifyVisibleElement(
"have.text",
ssoText.gitSignInText
);
});
it("Should verify Password login page elements", () => {
common.navigateToManageSSO();
cy.get(ssoSelector.password).should("be.visible").click();
cy.get(ssoSelector.cardTitle)
.should(($el) => {
expect($el.contents().first().text().trim()).to.eq(
ssoText.passwordTitle
);
})
.and("be.visible");
cy.get(ssoSelector.passwordEnableToggle).should("be.visible");
SSO.passwordPageElements();
common.logout();
});
it("Should verify the login and sign up page", () => {
common.logout();
SSO.signInPageElements();
cy.appUILogin();
common.navigateToManageSSO();
cy.get(ssoSelector.enableSignUpToggle).then(($el) => {
if (!$el.is(":checked")) {
cy.get(ssoSelector.enableSignUpToggle).check();
}
});
cy.get(ssoSelector.saveButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, ssoText.ssoToast);
common.logout();
SSO.signInPageElements();
cy.get(commonSelectors.signInSubHeader).verifyVisibleElement(
"have.text",
commonText.signInSubHeader
);
cy.get(commonSelectors.createAnAccountLink).click();
SSO.SignUpPageElements();
cy.get(commonSelectors.signInRedirectLink).click();
cy.get(ssoSelector.signInHeader).verifyVisibleElement(
"have.text",
ssoText.signInHeader
);
cy.appUILogin();
common.navigateToManageSSO();
cy.get(ssoSelector.google).click();
cy.get(ssoSelector.googleEnableToggle).uncheck();
common.logout();
cy.get(commonSelectors.createAnAccountLink).click();
cy.notVisible(ssoSelector.googleSSOText);
cy.get(commonSelectors.signInRedirectLink).click();
cy.appUILogin();
common.navigateToManageSSO();
cy.get(ssoSelector.git).click();
cy.get(ssoSelector.gitEnableToggle).uncheck();
common.logout();
cy.get(commonSelectors.createAnAccountLink).click();
cy.notVisible(ssoSelector.googleSSOText);
cy.notVisible(ssoSelector.gitSSOText);
cy.get(commonSelectors.signInRedirectLink).click();
cy.appUILogin();
common.navigateToManageSSO();
cy.get(ssoSelector.enableSignUpToggle).uncheck();
cy.get(ssoSelector.saveButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, ssoText.ssoToast);
common.logout();
cy.notVisible(commonSelectors.signInSubHeader);
});
});

View file

@ -1,122 +0,0 @@
import { ssoSelector } from "Selectors/manageSSO";
import * as common from "Support/utils/common";
import { ssoText } from "Texts/manageSSO";
import * as SSO from "Support/utils/manageSSO";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { usersSelector } from "Selectors/manageUsers";
import { usersText } from "Texts/manageUsers";
import * as archiveUser from "Support/utils/manageUsers";
import * as unarchiveUser from "Support/utils/manageUsers";
describe("SSO onboarding", () => {
before(() => {
cy.appUILogin();
SSO.enableSignUp();
SSO.enableGoogleSSO();
SSO.enableGitHubSSO();
common.logout();
SSO.updateId();
});
it("Should verify the enable signup functionality and GitHub SSO user onboarding", () => {
cy.appUILogin();
SSO.disableSignUp();
common.logout();
SSO.gitHubSSO(Cypress.env("git_user"), Cypress.env("sso_password"));
cy.verifyToastMessage(
commonSelectors.toastMessage,
ssoText.gitUserStatusToast
);
cy.appUILogin();
SSO.enableSignUp();
common.logout();
cy.get(ssoSelector.gitSSOText).click();
SSO.invitePageElements();
cy.clearAndType(commonSelectors.passwordInputField, "password");
cy.get(commonSelectors.acceptInviteButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.swPasswordSuccessToast
);
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
common.logout();
});
it("Should verify Google SSO user onboarding", () => {
cy.visit("/");
// cy.wait(4000);
// cy.get(ssoSelector.googleSSOText).click();
// cy.origin("https://accounts.google.com/", () => {
// cy.get(".d2laFc").first().click();
// cy.wait(3000);
// });
SSO.googleSSO(Cypress.env("google_user"), Cypress.env("sso_password"));
cy.clearAndType(commonSelectors.passwordInputField, "password");
cy.get(commonSelectors.acceptInviteButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.swPasswordSuccessToast
);
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
common.logout();
});
it("Should verify archived user login using SSO", () => {
cy.appUILogin();
archiveUser.userStatus(Cypress.env("git_user"));
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.archivedToast
);
common.logout();
SSO.gitHubSSO(Cypress.env("git_user"), Cypress.env("sso_password"));
cy.verifyToastMessage(
commonSelectors.toastMessage,
ssoText.gitUserStatusToast
);
cy.appUILogin();
unarchiveUser.userStatus(Cypress.env("git_user"));
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.unarchivedToast
);
common.logout();
cy.get(ssoSelector.gitSSOText).click();
cy.wait(500);
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
common.logout();
});
it("Should verify GitHub and Google SSO login", () => {
cy.visit("/");
SSO.loginbyGitHub(Cypress.env("git_user"), Cypress.env("sso_password"));
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
common.logout();
cy.reload();
cy.wait(500);
SSO.googleSSO(Cypress.env("google_user"), Cypress.env("sso_password"));
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
common.logout();
});
});

View file

@ -1,234 +0,0 @@
import { commonSelectors } from "Selectors/common";
import { fake } from "Fixtures/fake";
import { usersSelector } from "Selectors/manageUsers";
import { usersText } from "Texts/manageUsers";
import * as users from "Support/utils/manageUsers";
import * as common from "Support/utils/common";
import { path } from "Texts/common";
import { commonText } from "Texts/common";
const data = {};
data.firstName = fake.firstName;
data.lastName = fake.lastName.replaceAll("[^A-Za-z]", "");
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Manage Users for single workspace", () => {
beforeEach(() => {
cy.appUILogin();
});
it("Should verify the Manage users page", () => {
common.navigateToManageUsers();
users.manageUsersElements();
cy.get(usersSelector.cancelButton).click();
cy.get(usersSelector.usersElements.nameTitile).should("be.visible");
cy.get(usersSelector.inviteUserButton).click();
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.lastNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.emailError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.clearAndType(usersSelector.firstNameInput, data.firstName);
cy.get(usersSelector.lastNameInput).clear();
cy.get(usersSelector.emailInput).clear();
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.lastNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.emailError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.firstNameInput).clear();
cy.get(usersSelector.emailInput).clear();
cy.clearAndType(usersSelector.lastNameInput, data.lastName);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.emailError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.firstNameInput).clear();
cy.get(usersSelector.lastNameInput).clear();
cy.clearAndType(usersSelector.emailInput, data.email);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.lastNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.firstNameInput).clear();
cy.clearAndType(usersSelector.lastNameInput, data.lastName);
cy.clearAndType(usersSelector.emailInput, data.email);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.lastNameInput).clear();
cy.clearAndType(usersSelector.firstNameInput, data.firstName);
cy.clearAndType(usersSelector.emailInput, data.email);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.lastNameError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.get(usersSelector.emailInput).clear();
cy.clearAndType(usersSelector.firstNameInput, data.firstName);
cy.clearAndType(usersSelector.lastNameInput, data.lastName);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.emailError).verifyVisibleElement(
"have.text",
usersText.fieldRequired
);
cy.clearAndType(usersSelector.firstNameInput, data.firstName);
cy.clearAndType(usersSelector.lastNameInput, data.lastName);
cy.clearAndType(usersSelector.emailInput, usersText.adminUserEmail);
cy.get(usersSelector.createUserButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.exsitingEmail
);
});
it("Should verify the confirm invite page and new user account", () => {
common.navigateToManageUsers();
users.inviteUser(data.firstName, data.lastName, data.email);
users.confirmInviteElements();
cy.clearAndType(commonSelectors.passwordInputField, "pass");
cy.get(commonSelectors.acceptInviteButton).should("be.disabled");
cy.clearAndType(commonSelectors.passwordInputField, usersText.password);
cy.get(commonSelectors.acceptInviteButton).should("not.be.disabled");
cy.get(commonSelectors.acceptInviteButton).click();
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
cy.get(commonSelectors.workspaceName).click();
common.logout();
cy.appUILogin();
common.navigateToManageUsers();
common.searchUser(data.email);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get("td small").should("have.text", usersText.activeStatus);
});
common.logout();
});
it("Should verify the archive functionality", () => {
common.navigateToManageUsers();
common.searchUser(data.email);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get("td button").click();
});
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.archivedToast
);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get(usersSelector.userStatus, { timeout: 9000 }).should(
"have.text",
usersText.archivedStatus
);
});
common.logout();
cy.clearAndType(commonSelectors.workEmailInputField, data.email);
cy.clearAndType(commonSelectors.passwordInputField, usersText.password);
cy.get(commonSelectors.signInButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
"Your account is not active"
);
cy.appUILogin();
common.navigateToManageUsers();
common.searchUser(data.email);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get("td button").click();
});
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.unarchivedToast
);
cy.window().then((win) => {
cy.stub(win, "prompt").returns(win.prompt).as("copyToClipboardPrompt");
});
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get("td img").click();
});
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.inviteCopiedToast
);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get(usersSelector.userStatus, { timeout: 9000 }).should(
"have.text",
usersText.invitedStatus
);
});
cy.get("@copyToClipboardPrompt").then((prompt) => {
common.logout();
cy.visit(prompt.args[0][1]);
cy.url().should("include", path.confirmInvite);
});
cy.get(usersSelector.acceptInvite).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
"Added to the workspace successfully."
);
common.logout();
cy.appUILogin();
common.navigateToManageUsers();
common.searchUser(data.email);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get("td small").should("have.text", usersText.activeStatus);
});
});
});

View file

@ -1,88 +1,110 @@
import { appVersionSelectors } from "Selectors/exportImport";
import { editVersionSelectors } from "Selectors/version";
import { editVersionText, releasedVersionText, deleteVersionText } from "Texts/version";
import {
editVersionText,
releasedVersionText,
deleteVersionText,
} from "Texts/version";
import { createNewVersion } from "Support/utils/exportImport";
import { navigateToCreateNewVersionModal, verifyElementsOfCreateNewVersionModal, navigateToEditVersionModal, editVersionAndVerify, deleteVersionAndVerify, releasedVersionAndVerify, verifyDuplicateVersion, verifyVersionAfterPreview } from "Support/utils/version";
import {
navigateToCreateNewVersionModal,
verifyElementsOfCreateNewVersionModal,
navigateToEditVersionModal,
editVersionAndVerify,
deleteVersionAndVerify,
releasedVersionAndVerify,
verifyDuplicateVersion,
verifyVersionAfterPreview,
} from "Support/utils/version";
import { fake } from "Fixtures/fake";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { verifyModal, closeModal, navigateToAppEditor } from "Support/utils/common";
import {
verifyModal,
closeModal,
navigateToAppEditor,
} from "Support/utils/common";
import { buttonText } from "Texts/button";
import { verifyComponent, deleteComponentAndVerify } from "Support/utils/basicComponents";
import {
verifyComponent,
deleteComponentAndVerify,
} from "Support/utils/basicComponents";
describe("App Version Functionality", () => {
var data = {};
data.appName = `${fake.companyName}-App`;
let currentVersion = "";
let newVersion = [];
let versionFrom = "";
beforeEach(() => {
cy.appUILogin();
});
var data = {};
data.appName = `${fake.companyName}-App`;
let currentVersion = "";
let newVersion = [];
let versionFrom = "";
beforeEach(() => {
cy.appUILogin();
});
it("Verify the elements of the version module", () => {
cy.createApp();
cy.get(appVersionSelectors.appVersionLabel).should("be.visible");
cy.renameApp(data.appName);
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"have.value",
data.appName
);
cy.waitForAutoSave();
navigateToCreateNewVersionModal(currentVersion = "v1");
verifyElementsOfCreateNewVersionModal(currentVersion = ["v1"]);
it("Verify the elements of the version module", () => {
cy.createApp();
cy.get(appVersionSelectors.appVersionLabel).should("be.visible");
cy.renameApp(data.appName);
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"have.value",
data.appName
);
cy.waitForAutoSave();
navigateToCreateNewVersionModal((currentVersion = "v1"));
verifyElementsOfCreateNewVersionModal((currentVersion = ["v1"]));
navigateToEditVersionModal(currentVersion = "v1")
verifyModal(
editVersionText.editVersionTitle,
editVersionText.saveButton,
editVersionSelectors.versionNameInputField
);
closeModal(commonText.closeButton);
});
navigateToEditVersionModal((currentVersion = "v1"));
verifyModal(
editVersionText.editVersionTitle,
editVersionText.saveButton,
editVersionSelectors.versionNameInputField
);
closeModal(commonText.closeButton);
});
it("Verify all functionality for the app version", () => {
navigateToAppEditor(data.appName);
cy.get('[data-cy="widget-list-box-table"]').should("be.visible");
cy.get(".driver-close-btn").click();
it("Verify all functionality for the app version", () => {
navigateToAppEditor(data.appName);
cy.get('[data-cy="widget-list-box-table"]').should("be.visible");
cy.get(".driver-close-btn").click();
cy.dragAndDropWidget("Toggle Switch", 50, 50);
verifyComponent("toggleswitch1");
cy.dragAndDropWidget("Toggle Switch", 50, 50);
verifyComponent("toggleswitch1");
navigateToCreateNewVersionModal(currentVersion = "v1");
createNewVersion((newVersion = ["v2"]), versionFrom = "v1");
verifyComponent("toggleswitch1");
deleteComponentAndVerify("toggleswitch1");
navigateToCreateNewVersionModal((currentVersion = "v1"));
createNewVersion((newVersion = ["v2"]), (versionFrom = "v1"));
verifyComponent("toggleswitch1");
deleteComponentAndVerify("toggleswitch1");
cy.dragAndDropWidget(buttonText.defaultWidgetText);
verifyComponent("button1");
navigateToCreateNewVersionModal((currentVersion = "v2"));
createNewVersion((newVersion = ["v3"]), (versionFrom = "v2"));
verifyComponent("button1");
cy.dragAndDropWidget(buttonText.defaultWidgetText);
verifyComponent("button1");
navigateToCreateNewVersionModal(currentVersion = "v2");
createNewVersion((newVersion = ["v3"]), versionFrom = "v2");
verifyComponent("button1");
navigateToCreateNewVersionModal((currentVersion = "v3"));
createNewVersion((newVersion = ["v4"]), (versionFrom = "v1"));
verifyComponent("toggleswitch1");
navigateToCreateNewVersionModal(currentVersion = "v3");
createNewVersion((newVersion = ["v4"]), versionFrom = "v1");
verifyComponent("toggleswitch1");
editVersionAndVerify(
(currentVersion = "v4"),
(newVersion = ["v5"]),
editVersionText.VersionNameUpdatedToastMessage
);
navigateToCreateNewVersionModal((currentVersion = "v5"));
verifyDuplicateVersion((newVersion = ["v5"]), (versionFrom = "v5"));
closeModal(commonText.closeButton);
deleteVersionAndVerify(
(currentVersion = "v5"),
deleteVersionText.deleteToastMessage((currentVersion = "v5"))
);
editVersionAndVerify(currentVersion = "v4", newVersion = ["v5"], editVersionText.VersionNameUpdatedToastMessage)
navigateToCreateNewVersionModal(currentVersion = "v5");
verifyDuplicateVersion((newVersion = ["v5"]), versionFrom = "v5")
closeModal(commonText.closeButton);
deleteVersionAndVerify(currentVersion = "v5", deleteVersionText.deleteToastMessage(currentVersion = "v5"));
cy.reload();
cy.wait(7000); //temp fix need to update
releasedVersionAndVerify((currentVersion = "v3"));
navigateToCreateNewVersionModal((currentVersion = "v3"));
createNewVersion((newVersion = ["v6"]), (versionFrom = "v3"));
cy.reload();
releasedVersionAndVerify(currentVersion = "v3");
editVersionAndVerify(currentVersion = "v3", newVersion = ["v5"], releasedVersionText.cannotUpdateReleasedVersionToastMessage);
closeModal(commonText.closeButton);
deleteVersionAndVerify(currentVersion = "v3", releasedVersionText.cannotDeleteReleasedVersionToastMessage)
navigateToCreateNewVersionModal(currentVersion = "v3");
createNewVersion((newVersion = ["v6"]), versionFrom = "v3");
verifyVersionAfterPreview(currentVersion = "v6")
cy.go('back');
})
verifyVersionAfterPreview((currentVersion = "v6"));
cy.go("back");
});
});

View file

@ -1,3 +1,4 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { bigqueryText } from "Texts/bigquery";
@ -7,22 +8,23 @@ import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { commonText } from "Texts/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source BigQuery", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
cy.intercept("GET", "/api/v2/data_sources");
});
it("Should verify elements on BigQuery connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -46,7 +48,7 @@ describe("Data source BigQuery", () => {
bigqueryText.bigQuery
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", bigqueryText.bigQuery);
cy.get('[data-cy="data-source-bigquery"]').click();
@ -87,7 +89,7 @@ describe("Data source BigQuery", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
bigqueryText.errorInvalidEmailId
);
@ -98,7 +100,7 @@ describe("Data source BigQuery", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
bigqueryText.cypressBigQuery
`cypress-${data.lastName}-bigquery`
);
fillDataSourceTextField(
@ -119,12 +121,11 @@ describe("Data source BigQuery", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get("#radix-2").click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", bigqueryText.cypressBigQuery)
.find("button")
.invoke("show")
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-bigquery-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-bigquery`);
deleteDatasource(`cypress-${data.lastName}-bigquery`);
});
});

View file

@ -1,7 +1,10 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { commonText } from "Texts/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -13,21 +16,19 @@ import {
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -48,7 +49,7 @@ describe("Data sources", () => {
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("ClickHouse");
cy.get("[data-cy*='data-source-']").eq(0).should("contain", "ClickHouse");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "ClickHouse");
cy.get('[data-cy="data-source-clickhouse"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -122,7 +123,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL, { timeout: 60000 })
cy.get('[data-cy="connection-alert-text"]', { timeout: 60000 })
.scrollIntoView()
.verifyVisibleElement("have.text", "getaddrinfo ENOTFOUND undefined");
});
@ -132,7 +133,7 @@ describe("Data sources", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
"cypress-clickhouse"
`cypress-${data.lastName}-clickhouse`
);
fillDataSourceTextField(
@ -155,9 +156,7 @@ describe("Data sources", () => {
cy.get(postgreSqlSelector.passwordTextField).type(
Cypress.env("clickhouse_password")
);
cy.get(".css-1e1a1lx-control > .css-s59k37-ValueContainer")
.click()
.type(`HTTP{enter}`);
cy.get(".react-select__input-container").click().type(`HTTP{enter}`);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
@ -170,11 +169,9 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", "cypress-clickhouse")
.find("button")
.invoke("show")
.should("be.visible");
cy.get(
`[data-cy="cypress-${data.lastName}-clickhouse-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-clickhouse`);
deleteDatasource(`cypress-${data.lastName}-clickhouse`);
});
});

View file

@ -1,7 +1,10 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { commonText } from "Texts/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -13,23 +16,20 @@ import {
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
@ -48,7 +48,7 @@ describe("Data sources", () => {
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("CosmosDB");
cy.get("[data-cy*='data-source-']").eq(0).should("contain", "CosmosDB");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "CosmosDB");
cy.get('[data-cy="data-source-cosmosdb"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -88,7 +88,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
"Invalid URL"
);
@ -96,20 +96,19 @@ describe("Data sources", () => {
it("Should verify the functionality of CosmosDB connection form.", () => {
selectDataSource("CosmosDB");
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
"cypress-cosmosdb"
`cypress-${data.lastName}-cosmosdb`
);
fillDataSourceTextField(
"End point",
'https://your-account.documents.azure.com',
"https://your-account.documents.azure.com",
Cypress.env("cosmosdb_end_point")
);
fillDataSourceTextField(
'Key',
'Enter your key',
"Key",
"Enter your key",
Cypress.env("cosmosdb_key")
);
@ -124,11 +123,9 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", "cypress-cosmosdb")
.find("button")
.invoke('show')
.should("be.visible");
cy.get(
`[data-cy="cypress-${data.lastName}-cosmosdb-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-cosmosdb`);
deleteDatasource(`cypress-${data.lastName}-cosmosdb`);
});
});

View file

@ -1,7 +1,11 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { commonText } from "Texts/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -13,21 +17,19 @@ import {
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -47,12 +49,8 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"CouchDB"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", "CouchDB");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("CouchDB");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "CouchDB");
cy.get('[data-cy="data-source-couchdb"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -82,7 +80,7 @@ describe("Data sources", () => {
cy.get('[data-cy="label-protocol"]').verifyVisibleElement(
"have.text",
'Protocol'
"Protocol"
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
@ -111,9 +109,9 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
'Invalid URL'
"Invalid URL"
);
});
@ -122,33 +120,30 @@ describe("Data sources", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
postgreSqlText.psqlName
`cypress-${data.lastName}-couchdb`
);
fillDataSourceTextField(
postgreSqlText.labelHost,
'',
"",
Cypress.env("couchdb_host")
);
fillDataSourceTextField(
postgreSqlText.labelPort,
'5984 ',
"5984"
);
fillDataSourceTextField(postgreSqlText.labelPort, "5984 ", "5984");
fillDataSourceTextField(
postgreSqlText.labelDbName,
'database name',
'{del}'
"database name",
"{del}"
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
'username for couchDB',
"username for couchDB",
Cypress.env("couchdb_user")
);
cy.get('.css-1e1a1lx-control > .css-s59k37-ValueContainer').type('HTTP{enter}')
cy.get(".react-select__input-container").type("HTTP{enter}");
cy.get(postgreSqlSelector.passwordTextField).type(
Cypress.env("couchdb_password"), {log:false}
Cypress.env("couchdb_password"),
{ log: false }
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
@ -162,11 +157,9 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", postgreSqlText.psqlName)
.find("button")
.invoke("show")
.should("be.visible");
cy.get(
`[data-cy="cypress-${data.lastName}-couchdb-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-couchdb`);
deleteDatasource(`cypress-${data.lastName}-couchdb`);
});
});

View file

@ -1,28 +1,33 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { dynamoDbText } from "Texts/dynamodb";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
import {
closeDSModal,
verifyCouldnotConnectWithAlert,
deleteDatasource,
} from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source DynamoDB", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on DynamoDB connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -46,7 +51,7 @@ describe("Data source DynamoDB", () => {
dynamoDbText.dynamoDb
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", dynamoDbText.dynamoDb);
cy.get('[data-cy="data-source-dynamodb"]').click();
@ -94,7 +99,7 @@ describe("Data source DynamoDB", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
dynamoDbText.errorMissingRegion
);
@ -105,7 +110,7 @@ describe("Data source DynamoDB", () => {
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
dynamoDbText.cypressDynamoDb
`cypress-${data.lastName}-dynamodb`
);
cy.get('[data-cy="label-region"]')
@ -158,9 +163,10 @@ describe("Data source DynamoDB", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("contains.text", dynamoDbText.cypressDynamoDb)
.should("be.visible");
cy.get(
`[data-cy="cypress-${data.lastName}-dynamodb-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-dynamodb`);
deleteDatasource(`cypress-${data.lastName}-dynamodb`);
});
});

View file

@ -1,28 +1,32 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { elasticsearchText } from "Texts/elasticsearch";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
import {
verifyCouldnotConnectWithAlert,
deleteDatasource,
closeDSModal,
} from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source Elasticsearch", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on Elasticsearch connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -46,7 +50,7 @@ describe("Data source Elasticsearch", () => {
elasticsearchText.elasticSearch
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", elasticsearchText.elasticSearch);
cy.get('[data-cy="data-source-elasticsearch"]').click();
@ -105,7 +109,7 @@ describe("Data source Elasticsearch", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
elasticsearchText.errorConnectionRefused
);
@ -116,7 +120,7 @@ describe("Data source Elasticsearch", () => {
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
elasticsearchText.cypressElasticsearch
`cypress-${data.lastName}-elasticsearch`
);
fillDataSourceTextField(
@ -153,7 +157,9 @@ describe("Data source Elasticsearch", () => {
"elasticsearch_user"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert("write EPROTO C062440602000000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:355:");
verifyCouldnotConnectWithAlert(
"write EPROTO 4041EA0502000000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:355:"
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
@ -164,11 +170,13 @@ describe("Data source Elasticsearch", () => {
.clear()
.type("elasticsearch_password");
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert("write EPROTO C062440602000000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:355:");
verifyCouldnotConnectWithAlert(
"write EPROTO 4041EA0502000000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:355:"
);
cy.get(postgreSqlSelector.passwordTextField)
.clear()
.type(Cypress.env("elasticsearch_password"));
cy.get('.form-check-input').click()
cy.get(".form-check-input").click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
@ -181,9 +189,13 @@ describe("Data source Elasticsearch", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", elasticsearchText.cypressElasticsearch)
.should("be.visible");
cy.get(
`[data-cy="cypress-${data.lastName}-elasticsearch-button"]`
).verifyVisibleElement(
"have.text",
`cypress-${data.lastName}-elasticsearch`
);
deleteDatasource(`cypress-${data.lastName}-elasticsearch`);
});
});

View file

@ -1,27 +1,31 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { firestoreText } from "Texts/firestore";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
verifyCouldnotConnectWithAlert,
deleteDatasource,
closeDSModal,
} from "Support/utils/dataSource";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source Firestore", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on Firestore connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -45,7 +49,7 @@ describe("Data source Firestore", () => {
firestoreText.firestore
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", firestoreText.firestore);
cy.get('[data-cy="data-source-firestore"]').click();
@ -86,7 +90,7 @@ describe("Data source Firestore", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
firestoreText.errorGcpKeyCouldNotBeParsed
);
@ -97,7 +101,7 @@ describe("Data source Firestore", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
firestoreText.cypressFirestore
`cypress-${data.lastName}-firestore`
);
fillDataSourceTextField(
@ -118,11 +122,10 @@ describe("Data source Firestore", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("contain.text", firestoreText.cypressFirestore)
.find("button")
.invoke("show")
.should("be.visible");
cy.get(
`[data-cy="cypress-${data.lastName}-firestore-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-firestore`);
deleteDatasource(`cypress-${data.lastName}-firestore`);
});
});

View file

@ -1,6 +1,7 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addQuery,
@ -12,22 +13,25 @@ import {
addGuiQuery,
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
import {
verifyCouldnotConnectWithAlert,
deleteDatasource,
closeDSModal,
} from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -47,12 +51,8 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"InfluxDB"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", "InfluxDB");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("InfluxDB");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "InfluxDB");
cy.get('[data-cy="data-source-influxdb"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -102,9 +102,9 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
'Invalid URL'
"Invalid URL"
);
});
@ -113,20 +113,21 @@ describe("Data sources", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
postgreSqlText.psqlName
`cypress-${data.lastName}-influxdb`
);
cy.clearAndType(
'[data-cy="api-token-text-field"]',
Cypress.env("influxdb_token")
);
fillDataSourceTextField(
postgreSqlText.labelHost,
'',
"",
Cypress.env("influxdb_host")
);
fillDataSourceTextField(
postgreSqlText.labelPort,
'8086 ',
"8086"
);
cy.get('.css-1e1a1lx-control > .css-s59k37-ValueContainer').click().type('HTTP{enter}')
fillDataSourceTextField(postgreSqlText.labelPort, "8086 ", "8086");
cy.get(".react-select__input-container").click().type("HTTP{enter}");
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
@ -139,11 +140,10 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", postgreSqlText.psqlName)
.find("button")
.invoke('show')
.should("be.visible");
cy.get(
`[data-cy="cypress-${data.lastName}-influxdb-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-influxdb`);
deleteDatasource(`cypress-${data.lastName}-influxdb`);
});
});

View file

@ -1,6 +1,6 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addQuery,
@ -12,22 +12,19 @@ import {
addGuiQuery,
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -47,12 +44,8 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"MariaDB"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", "MariaDB");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("MariaDB");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "MariaDB");
cy.get('[data-cy="data-source-mariadb"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -88,7 +81,7 @@ describe("Data sources", () => {
"have.text",
"Database"
);
cy.get(postgreSqlSelector.labelSSLCertificate).verifyVisibleElement(
"have.text",
postgreSqlText.sslCertificate
@ -112,18 +105,14 @@ describe("Data sources", () => {
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).scrollIntoView().verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect
);
cy.get(postgreSqlSelector.connectionFailedText)
.scrollIntoView()
.verifyVisibleElement("have.text", postgreSqlText.couldNotConnect);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"contain.text",
'(conn=-1, no: 45028, SQLState: HY000) retrieve connection from pool timeout after '
).and('contain.text', ' (pool connections: active=0 idle=0 limit=5)');
// cy.get('[data-cy="connection-alert-text"]').should("be.visible")
});
it("Should verify the functionality of PostgreSQL connection form.", () => {
@ -131,34 +120,33 @@ describe("Data sources", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
postgreSqlText.psqlName
"cypress-mariadb"
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
Cypress.env("pg_host")
Cypress.env("mariadb_host")
);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
"5432"
);
fillDataSourceTextField(
"Database",
"Enter name of the database",
"postgres"
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"postgres"
Cypress.env("mariadb_user")
);
cy.get(postgreSqlSelector.passwordTextField).type(
Cypress.env("pg_password")
Cypress.env("mariadb_password")
);
cy.get('[data-cy="label-database"]').verifyVisibleElement("have.text", "Database")
cy.get('[data-cy="database-text-field"]').should("be.visible").invoke('attr', 'placeholder').should('contain', 'Enter name of the database')
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
@ -170,10 +158,11 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", postgreSqlText.psqlName)
.find("button")
.should("be.visible");
cy.get('[data-cy="cypress-mariadb-button"]').verifyVisibleElement(
"have.text",
"cypress-mariadb"
);
deleteDatasource("cypress-mariadb");
});
});

View file

@ -1,12 +1,19 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { mongoDbText } from "Texts/mongoDb";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { connectMongo, openMongoQueryEditor,selectQueryType } from "Support/utils/mongoDB";
import {
connectMongo,
openMongoQueryEditor,
selectQueryType,
} from "Support/utils/mongoDB";
import {
verifyCouldnotConnectWithAlert,
@ -16,21 +23,19 @@ import {
addInput,
} from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source MongoDB", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on MongoDB connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -54,7 +59,7 @@ describe("Data source MongoDB", () => {
mongoDbText.mongoDb
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", mongoDbText.mongoDb);
cy.get('[data-cy="data-source-mongodb"]').click();
@ -110,7 +115,7 @@ describe("Data source MongoDB", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
"connect ECONNREFUSED ::1:27017"
);
@ -145,9 +150,9 @@ describe("Data source MongoDB", () => {
}).verifyVisibleElement("have.text", postgreSqlText.couldNotConnect, {
timeout: 95000,
});
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
'Invalid scheme, expected connection string to start with "mongodb://" or "mongodb+srv://"'
"Cannot read properties of null (reading '2')"
);
verifyCouldnotConnectWithAlert(mongoDbText.errorInvalisScheme);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
@ -161,7 +166,7 @@ describe("Data source MongoDB", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
mongoDbText.cypressMongoDb
`cypress-${data.lastName}-mongodb`
);
cy.get('[data-cy="query-select-dropdown"]').type(
@ -186,173 +191,194 @@ describe("Data source MongoDB", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", mongoDbText.cypressMongoDb)
.find("button")
.invoke("show")
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-mongodb-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-mongodb`);
deleteDatasource(`cypress-${data.lastName}-mongodb`);
});
it.only("Should verify the queries of MongoDB.", () => {
it.skip("Should verify the queries of MongoDB.", () => {
connectMongo();
openMongoQueryEditor();
resizeQueryPanel();
selectQueryType('Delete Many')
addInput('collection', 'test')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
selectQueryType("Delete Many");
addInput("collection", "test");
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
selectQueryType('List Collections')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','[{"name":"test"') //'root:[] 0 items'
selectQueryType("List Collections");
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '[{"name":"test"'); //'root:[] 0 items'
selectQueryType("Insert One");
addInput("collection", "test");
addInput("document", '{name:"mike"}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '{"acknowledged":true,"insertedId"');
selectQueryType('Insert One')
addInput('collection', 'test')
addInput('document', '{name:"mike"}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','{"acknowledged":true,"insertedId"')
selectQueryType("Find One");
addInput("collection", "test");
addInput("filter", '{name:"mike"}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '"name":"mike"}');
selectQueryType('Find One')
addInput('collection', 'test')
addInput('filter', '{name:"mike"}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','"name":"mike"}')
selectQueryType("Find many");
addInput("collection", "test");
addInput("filter", '{name:"mike"}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '"name":"mike"}');
selectQueryType('Find many')
addInput('collection', 'test')
addInput('filter', '{name:"mike"}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','"name":"mike"}')
selectQueryType("Total Count");
addInput("collection", "test");
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '{"count":');
selectQueryType('Total Count')
addInput('collection', 'test')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','{"count":')
selectQueryType("Count");
addInput("collection", "test");
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '{"count":');
selectQueryType('Count')
addInput('collection', 'test')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','{"count":');
selectQueryType("Distinct");
addInput("collection", "test");
addInput("field", "name");
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '["mike"]');
selectQueryType("Insert Many");
addInput("collection", "test");
addInput(
"documents",
'[{_id:331, name:"Nina"},{_id:441, name:"mina"}, {_id:4441, name:"Steph"}, {_id:41, name:"Mark"},{_id:3131, name:"Lina"}]'
);
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
addInput("documents", '[{_id:3113, name:"Nina"},{_id:414, name:"mina"}]');
query("preview");
verifypreview(
"raw",
'{"acknowledged":true,"insertedCount":2,"insertedIds":{"0":3113,"1":414}}'
);
selectQueryType('Distinct')
addInput('collection', 'test')
addInput('field', 'name')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','["mike"]');
selectQueryType("Update One");
addInput("collection", "test");
addInput("filter", '{name:"mina"}');
addInput("update", '{$set:{name: "mike2023"}}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview(
"raw",
'{"acknowledged":true,"modifiedCount":1,"upsertedId":null,"upsertedCount":0'
);
selectQueryType("Update Many");
addInput("collection", "test");
addInput("filter", '{name:"Nina"}');
addInput("update", '{$set:{name: "mike22222"}}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
addInput("filter", '{name:"mike22222"}');
addInput("update", '{$set:{name: "Mark"}}');
query("preview");
verifypreview(
"raw",
'{"acknowledged":true,"modifiedCount":2,"upsertedId":null,"upsertedCount":0'
);
selectQueryType('Insert Many')
addInput('collection', 'test')
addInput('documents', '[{_id:331, name:"Nina"},{_id:441, name:"mina"}, {_id:4441, name:"Steph"}, {_id:41, name:"Mark"},{_id:3131, name:"Lina"}]')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
addInput('documents', '[{_id:3113, name:"Nina"},{_id:414, name:"mina"}]')
query('preview')
verifypreview('raw','{"acknowledged":true,"insertedCount":2,"insertedIds":{"0":3113,"1":414}}');
selectQueryType("Replace One");
addInput("collection", "test");
addInput("filter", '{name:"mike"}');
addInput("replacement", '{name: "mike2023"}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
addInput("filter", '{name:"mike"}');
addInput("replacement", '{name: "Nina"}');
query("preview");
verifypreview(
"raw",
'{"acknowledged":true,"modifiedCount":1,"upsertedId":null,"upsertedCount":0'
);
selectQueryType('Update One')
addInput('collection', 'test')
addInput('filter', '{name:"mina"}')
addInput('update', '{$set:{name: "mike2023"}}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','{"acknowledged":true,"modifiedCount":1,"upsertedId":null,"upsertedCount":0');
selectQueryType("Find One and Update");
addInput("collection", "test");
addInput("filter", '{name:"mike"}');
addInput("update", '{$set:{name: "mike2023"}}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
addInput("filter", '{name:"Mark"}');
addInput("update", '{$set:{name: "Nina"}}');
query("preview");
verifypreview(
"raw",
'{"lastErrorObject":{"n":1,"updatedExisting":true},"value":{"_id":'
);
selectQueryType('Update Many')
addInput('collection', 'test')
addInput('filter', '{name:"Nina"}')
addInput('update', '{$set:{name: "mike22222"}}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
addInput('filter', '{name:"mike22222"}')
addInput('update', '{$set:{name: "Mark"}}')
query('preview')
verifypreview('raw','{"acknowledged":true,"modifiedCount":2,"upsertedId":null,"upsertedCount":0');
selectQueryType("Find One and Replace");
addInput("collection", "test");
addInput("filter", '{name:"mike"}');
addInput("replacement", '{name: "mike2023"}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
addInput("filter", '{name:"mike2023"}');
addInput("replacement", '{name: "Nina"}');
query("preview");
verifypreview(
"raw",
'{"lastErrorObject":{"n":1,"updatedExisting":true},"value":{"_id":'
);
selectQueryType('Replace One')
addInput('collection', 'test')
addInput('filter', '{name:"mike"}')
addInput('replacement', '{name: "mike2023"}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
addInput('filter', '{name:"mike"}')
addInput('replacement', '{name: "Nina"}')
query('preview')
verifypreview('raw','{"acknowledged":true,"modifiedCount":1,"upsertedId":null,"upsertedCount":0');
selectQueryType("Find One and Delete");
addInput("collection", "test");
addInput("filter", '{name:"Nina"}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
addInput("filter", '{name:"mike2023"}');
query("preview");
verifypreview("raw", '{"lastErrorObject":{"n":1},"value":{"_id":');
selectQueryType('Find One and Update')
addInput('collection', 'test')
addInput('filter', '{name:"mike"}')
addInput('update', '{$set:{name: "mike2023"}}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
addInput('filter', '{name:"Mark"}')
addInput('update', '{$set:{name: "Nina"}}')
query('preview')
verifypreview('raw','{"lastErrorObject":{"n":1,"updatedExisting":true},"value":{"_id":');
selectQueryType("Delete One");
addInput("collection", "test");
addInput("filter", '{name:"mike"}');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
addInput("filter", '{name:"Lina"}');
query("preview");
verifypreview("raw", '{"acknowledged":true,"deletedCount":1}');
selectQueryType('Find One and Replace')
addInput('collection', 'test')
addInput('filter', '{name:"mike"}')
addInput('replacement', '{name: "mike2023"}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
addInput('filter', '{name:"mike2023"}')
addInput('replacement', '{name: "Nina"}')
query('preview')
verifypreview('raw','{"lastErrorObject":{"n":1,"updatedExisting":true},"value":{"_id":');
selectQueryType("Aggregate");
addInput("collection", "test");
addInput("pipeline", '[{$match:{name:"mike2023"}}, {$match:{_id:414}}]');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview("raw", '[{"_id":414,"name":"mike2023"}]');
selectQueryType('Find One and Delete')
addInput('collection', 'test')
addInput('filter', '{name:"Nina"}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
addInput('filter', '{name:"mike2023"}')
query('preview')
verifypreview('raw','{"lastErrorObject":{"n":1},"value":{"_id":');
selectQueryType('Delete One')
addInput('collection', 'test')
addInput('filter', '{name:"mike"}')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
addInput('filter', '{name:"Lina"}')
query('preview')
verifypreview('raw','{"acknowledged":true,"deletedCount":1}');
selectQueryType('Aggregate')
addInput('collection', 'test')
addInput('pipeline', '[{$match:{name:"mike2023"}}, {$match:{_id:414}}]')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','[{"_id":414,"name":"mike2023"}]');
selectQueryType('Operations')
addInput('collection', 'test')
addInput('operations', '[{insertOne:{name:"midhun"}}]')
query('run')
cy.verifyToastMessage('.go2072408551','Query (mongodb1) completed.')
query('preview')
verifypreview('raw','{"ok":1,"writeErrors":[],"writeConcernErrors":[],"insertedIds":[{"index":');
selectQueryType("Operations");
addInput("collection", "test");
addInput("operations", '[{insertOne:{name:"midhun"}}]');
query("run");
cy.verifyToastMessage(".go2072408551", "Query (mongodb1) completed.");
query("preview");
verifypreview(
"raw",
'{"ok":1,"writeErrors":[],"writeConcernErrors":[],"insertedIds":[{"index":'
);
});
});

View file

@ -1,8 +1,9 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { mySqlText } from "Texts/mysql";
import { commonSelectors } from "Selectors/common";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectDataSource,
@ -13,23 +14,26 @@ import {
addGuiQuery,
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
import {
closeDSModal,
deleteDatasource,
verifyCouldnotConnectWithAlert,
} from "Support/utils/dataSource";
import { realHover } from "cypress-real-events/commands/realHover";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources MySql", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on MySQL connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -50,7 +54,7 @@ describe("Data sources MySql", () => {
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("MySQL");
cy.get("[data-cy*='data-source-']").eq(0).should("contain", "MySQL");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "MySQL");
cy.get('[data-cy="data-source-mysql"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -113,7 +117,7 @@ describe("Data sources MySql", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
mySqlText.cypressMySql
`cypress-${data.lastName}-mysql`
);
fillDataSourceTextField(
@ -154,20 +158,24 @@ describe("Data sources MySql", () => {
"admin1"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert('ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client');
verifyCouldnotConnectWithAlert(
"ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client"
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
test/spec-updation-needed-to-fix-specs-on-github-actions
Cypress.env("mysql_user")
);
cy.get(postgreSqlSelector.passwordTextField).type("testpassword");
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert("ER_ACCESS_DENIED_ERROR: Access denied for user 'root'@'103.171.99.42' (using password: YES)");
verifyCouldnotConnectWithAlert(
"ER_ACCESS_DENIED_ERROR: Access denied for user 'root'@'103.171.99.42' (using password: YES)"
);
cy.get(postgreSqlSelector.passwordTextField).type(
`{selectAll}{backspace}${Cypress.env("mysql_password")}`, {log:false}
`{selectAll}{backspace}${Cypress.env("mysql_password")}`,
{ log: false }
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
@ -181,16 +189,16 @@ describe("Data sources MySql", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", mySqlText.cypressMySql)
.find("button")
.invoke('show')
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-mysql-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-mysql`);
deleteDatasource(`cypress-${data.lastName}-mysql`);
});
it.only("Should verify elements of the Query section.", () => {
cy.viewport(1200, 1300)
it.skip("Should verify elements of the Query section.", () => {
cy.viewport(1200, 1300);
selectDataSource("MySQL");
fillConnectionForm({
Host: Cypress.env("mysql_host"),
@ -244,7 +252,7 @@ describe("Data sources MySql", () => {
cy.get(`${postgreSqlSelector.querySelectDropdown}:eq(0)`)
.scrollIntoView()
.should("be.visible")
.click()
.click();
cy.contains("[id*=react-select-]", postgreSqlText.queryModeSql).should(
"have.text",
postgreSqlText.queryModeSql
@ -257,17 +265,16 @@ describe("Data sources MySql", () => {
cy.get(postgreSqlSelector.queryCreateAndRunButton)
.should("be.visible")
.click();
// cy.get('[data-cy="list-query-mysql1"]').should("be.visible").click();
// cy.get('[data-cy="list-query-mysql1"]').should("be.visible").click();
cy.get(postgreSqlSelector.labelTransformation)
.scrollIntoView()
.verifyVisibleElement("have.text", postgreSqlText.headerTransformations);
cy.wait(200)
cy.wait(200);
cy.get(postgreSqlSelector.toggleTransformation).parent().click();
cy.get(postgreSqlSelector.inputFieldTransformation).should("be.visible");
cy.get(postgreSqlSelector.toggleTransformation).parent().click();
cy.get(postgreSqlSelector.headerQueryPreview).verifyVisibleElement(
"have.text",
postgreSqlText.buttonLabelPreview
@ -301,7 +308,7 @@ describe("Data sources MySql", () => {
);
cy.get('[data-cy="label-records"]').verifyVisibleElement(
"have.text",
'Records'
"Records"
);
// cy.get(postgreSqlSelector.queryTabAdvanced)
@ -338,8 +345,15 @@ describe("Data sources MySql", () => {
postgreSqlText.labelNoEventhandler
);
cy.get('[data-cy="list-query-mysql1"]').verifyVisibleElement('have.text', 'mysql1');
cy.get('[class="row query-row query-row-selected"]').realHover().then(()=>{cy.get('[data-cy="delete-query-mysql1"]').click()})
cy.get('[data-cy="list-query-mysql1"]').verifyVisibleElement(
"have.text",
"mysql1"
);
cy.get('[class="row query-row query-row-selected"]')
.realHover()
.then(() => {
cy.get('[data-cy="delete-query-mysql1"]').click();
});
cy.get(postgreSqlSelector.deleteModalMessage).verifyVisibleElement(
"have.text",
postgreSqlText.dialogueTextDelete
@ -353,9 +367,9 @@ describe("Data sources MySql", () => {
.click();
});
it("Should verify CRUD operations on SQL Query.", () => {
let dbName ='7mmplik'
selectDataSource('MySQL');
it.skip("Should verify CRUD operations on SQL Query.", () => {
let dbName = "7mmplik";
selectDataSource("MySQL");
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
@ -398,7 +412,7 @@ describe("Data sources MySql", () => {
.should("be.visible", { timeout: 3000 })
.click();
cy.get('.p-3').should(
cy.get(".p-3").should(
"have.text",
`[{"Tables_in_testdb (${dbName})":"${dbName}"}]`
);
@ -418,27 +432,23 @@ describe("Data sources MySql", () => {
cy.get(postgreSqlSelector.queryPreviewButton).click();
cy.get('[class="tab-pane active"]', { timeout: 3000 }).should("be.visible");
cy.get(postgreSqlSelector.previewTabRaw).click();
cy.get('[class="tab-pane active"]').should("have.text", `{"fieldCount":0,"affectedRows":0,"insertId":0,"serverStatus":2,"warningCount":0,"message":"","protocol41":true,"changedRows":0}`);
addQuery(
"drop_table",
`DROP TABLE ${dbName}`,
mySqlText.cypressMySql
cy.get('[class="tab-pane active"]').should(
"have.text",
`{"fieldCount":0,"affectedRows":0,"insertId":0,"serverStatus":2,"warningCount":0,"message":"","protocol41":true,"changedRows":0}`
);
addQuery("drop_table", `DROP TABLE ${dbName}`, mySqlText.cypressMySql);
cy.get('[data-cy="list-query-existance_of_table"]').click();
cy.get(postgreSqlSelector.queryPreviewButton).click();
cy.get('[class="tab-pane active"]', { timeout: 3000 }).should("be.visible");
cy.get(postgreSqlSelector.previewTabRaw).click();
cy.get('[class="tab-pane active"]').should(
"have.text",
'[]'
);
cy.get('[class="tab-pane active"]').should("have.text", "[]");
// addWidgetsToAddUser();
});
it("Should verify bulk update", () => {
selectDataSource('MySQL');
it.skip("Should verify bulk update", () => {
selectDataSource("MySQL");
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
mySqlText.cypressMySql
@ -453,19 +463,8 @@ describe("Data sources MySql", () => {
openQueryEditor(mySqlText.cypressMySql);
cy.get('[class="query-pane"]').invoke("css", "height", "calc(85%)");
selectQueryMode(postgreSqlText.queryModeGui,);
selectQueryMode(postgreSqlText.queryModeGui);
addGuiQuery("name", "email");
cy.get(postgreSqlSelector.queryCreateAndRunButton).click();
});
});

View file

@ -1,6 +1,6 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addQuery,
@ -16,20 +16,18 @@ import {
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
// cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.reload();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
@ -51,7 +49,7 @@ describe("Data sources", () => {
postgreSqlText.postgreSQL
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", postgreSqlText.postgreSQL);
cy.get(postgreSqlSelector.postgresDataSource).click();
@ -164,7 +162,6 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", postgreSqlText.psqlName)
.find("button")

View file

@ -1,6 +1,7 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addQuery,
@ -12,22 +13,20 @@ import {
addGuiQuery,
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
import { deleteDatasource } from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -51,7 +50,7 @@ describe("Data sources", () => {
postgreSqlText.postgreSQL
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", postgreSqlText.postgreSQL);
cy.get(postgreSqlSelector.postgresDataSource).click();
@ -114,10 +113,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
postgreSqlText.serverNotSuppotSsl
);
cy.get('[data-cy="connection-alert-text"]').should("be.visible");
});
it("Should verify the functionality of PostgreSQL connection form.", () => {
@ -125,7 +121,7 @@ describe("Data sources", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
postgreSqlText.psqlName
`cypress-${data.lastName}-postgresql`
);
fillDataSourceTextField(
@ -138,6 +134,7 @@ describe("Data sources", () => {
postgreSqlText.placeholderEnterPort,
"5432"
);
cy.get('[data-cy="-toggle-input"]').uncheck();
fillDataSourceTextField(
postgreSqlText.labelDbName,
postgreSqlText.placeholderNameOfDB,
@ -164,14 +161,15 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", postgreSqlText.psqlName)
.find("button")
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-postgresql-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-postgresql`);
deleteDatasource(`cypress-${data.lastName}-postgresql`);
});
it.only("Should verify elements of the Query section.", () => {
it.skip("Should verify elements of the Query section.", () => {
selectDataSource(postgreSqlText.postgreSQL);
fillConnectionForm(
{
@ -362,7 +360,7 @@ describe("Data sources", () => {
.click();
});
it("Should verify CRUD operations on SQL Query.", () => {
it.skip("Should verify CRUD operations on SQL Query.", () => {
selectDataSource(postgreSqlText.postgreSQL);
cy.clearAndType(
@ -449,7 +447,7 @@ describe("Data sources", () => {
addWidgetsToAddUser();
});
it("Should verify bulk update", () => {
it.skip("Should verify bulk update", () => {
selectDataSource(postgreSqlText.postgreSQL);
fillConnectionForm({
Host: Cypress.env("pg_host"),

View file

@ -1,28 +1,32 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { redisText } from "Texts/redis";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
import {
verifyCouldnotConnectWithAlert,
deleteDatasource,
closeDSModal,
} from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source Redis", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connecti Redison form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -44,7 +48,7 @@ describe("Data source Redis", () => {
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(redisText.redis);
cy.get("[data-cy*='data-source-']")
.eq(0)
.eq(1)
.should("contain", redisText.redis);
cy.get('[data-cy="data-source-redis"]').click();
@ -71,7 +75,7 @@ describe("Data source Redis", () => {
);
cy.get(postgreSqlSelector.labelPassword).verifyVisibleElement(
"have.text",
'Password'
"Password"
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
@ -96,26 +100,30 @@ describe("Data source Redis", () => {
"have.text",
postgreSqlText.buttonTextSave
);
verifyCouldnotConnectWithAlert(redisText.errorMaxRetries);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
redisText.errorMaxRetries
);
});
it("Should verify the functionality of Redis connection form.", () => {
selectDataSource(redisText.redis);
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
redisText.cypressRedis
`cypress-${data.lastName}-redis`
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
"redis_host"
Cypress.env("redis_host")
);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
Cypress.env("redis_port")
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
@ -126,8 +134,10 @@ describe("Data source Redis", () => {
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorMaxRetries);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
"WRONGPASS invalid username-password pair or user is disabled."
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
@ -139,7 +149,10 @@ describe("Data source Redis", () => {
"108299"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorPort);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
redisText.errorPort
);
fillDataSourceTextField(
postgreSqlText.labelPort,
@ -150,7 +163,10 @@ describe("Data source Redis", () => {
`{selectAll}{backspace}"redis_password"`
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorInvalidUserOrPassword);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
"WRONGPASS invalid username-password pair or user is disabled."
);
cy.get(postgreSqlSelector.passwordTextField).type(
`{selectAll}{backspace}${Cypress.env("redis_password")}`
@ -161,7 +177,10 @@ describe("Data source Redis", () => {
"redis"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorInvalidUserOrPassword);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
"WRONGPASS invalid username-password pair or user is disabled."
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
@ -179,11 +198,11 @@ describe("Data source Redis", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", redisText.cypressRedis)
.find("button")
.invoke('show')
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-redis-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-redis`);
deleteDatasource(`cypress-${data.lastName}-redis`);
});
});

View file

@ -1,6 +1,6 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addQuery,
@ -16,20 +16,16 @@ import {
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.reload();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
@ -47,12 +43,8 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"RethinkDB"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", "RethinkDB");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("RethinkDB");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "RethinkDB");
cy.get('[data-cy="data-source-rethinkdb"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -109,7 +101,7 @@ describe("Data sources", () => {
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
'Could not connect to localhost:28015.connect ECONNREFUSED ::1:28015'
"Could not connect to localhost:28015.connect ECONNREFUSED ::1:28015"
);
});
@ -157,7 +149,6 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", postgreSqlText.psqlName)
.find("button")

View file

@ -1,28 +1,33 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { s3Selector } from "Selectors/awss3";
import { postgreSqlText } from "Texts/postgreSql";
import { s3Text } from "Texts/awss3";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
import {
verifyCouldnotConnectWithAlert,
deleteDatasource,
closeDSModal,
} from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources AWS S3", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on AWS S3 connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -43,7 +48,7 @@ describe("Data sources AWS S3", () => {
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(s3Text.awsS3);
cy.get("[data-cy*='data-source-']").eq(0).should("contain", s3Text.awsS3);
cy.get("[data-cy*='data-source-']").eq(1).should("contain", s3Text.awsS3);
cy.get(s3Selector.awsDatasource).click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -94,13 +99,19 @@ describe("Data sources AWS S3", () => {
"have.text",
postgreSqlText.buttonTextSave
);
verifyCouldnotConnectWithAlert(s3Text.alertRegionIsMissing);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
s3Text.alertRegionIsMissing
);
});
it("Should verify the functionality of AWS S3 connection form.", () => {
selectDataSource(s3Text.awsS3);
cy.clearAndType(s3Selector.dataSourceNameInput, s3Text.cypressAwsS3);
cy.clearAndType(
s3Selector.dataSourceNameInput,
`cypress-${data.lastName}-aws-s3`
);
fillDataSourceTextField(
s3Text.accessKey,
@ -109,7 +120,10 @@ describe("Data sources AWS S3", () => {
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.alertRegionIsMissing);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
s3Text.alertRegionIsMissing
);
fillDataSourceTextField(
"Secret key",
@ -119,7 +133,7 @@ describe("Data sources AWS S3", () => {
);
cy.get(s3Selector.regionLabel)
.parent()
.parent()
.next()
.find("input")
.type(`${s3Text.region}{enter}`);
@ -132,7 +146,10 @@ describe("Data sources AWS S3", () => {
.click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.alertInvalidUrl);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
s3Text.alertInvalidUrl
);
cy.get(s3Selector.customEndpointLabel)
.verifyVisibleElement("have.text", s3Text.customEndpoint)
.parent()
@ -147,7 +164,10 @@ describe("Data sources AWS S3", () => {
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.accessKeyError);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
s3Text.accessKeyError
);
fillDataSourceTextField(
s3Text.accessKey,
@ -163,7 +183,10 @@ describe("Data sources AWS S3", () => {
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.sinatureError);
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
s3Text.sinatureError
);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
@ -171,11 +194,10 @@ describe("Data sources AWS S3", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", s3Text.cypressAwsS3)
.find("button")
.invoke('show')
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-aws-s3-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-aws-s3`);
deleteDatasource(`cypress-${data.lastName}-aws-s3`);
});
});

View file

@ -16,20 +16,17 @@ import {
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
// cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.reload();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
@ -47,17 +44,13 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"SAP HANA"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain","SAP HANA");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("SAP HANA");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "SAP HANA");
cy.get('[data-cy="data-source-sap hana"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
"SAP HANA"
"SAP HANA"
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
@ -152,7 +145,6 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", postgreSqlText.psqlName)
.find("button")

View file

@ -1,26 +1,27 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { deleteDatasource, closeDSModal } from "Support/utils/dataSource";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source SMTP", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on SMTP connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -41,7 +42,7 @@ describe("Data source SMTP", () => {
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("SMTP");
cy.get("[data-cy*='data-source-']").eq(0).should("contain", "SMTP");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "SMTP");
cy.get('[data-cy="data-source-smtp"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -89,7 +90,7 @@ describe("Data source SMTP", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
"Invalid credentials"
);
@ -100,7 +101,7 @@ describe("Data source SMTP", () => {
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
"cypress-smtp"
`cypress-${data.lastName}-smtp`
);
fillDataSourceTextField(
@ -137,9 +138,10 @@ describe("Data source SMTP", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", "cypress-smtp")
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-smtp-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-smtp`);
deleteDatasource(`cypress-${data.lastName}-smtp`);
});
});

View file

@ -1,7 +1,10 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -16,18 +19,16 @@ import {
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
it("Should verify elements on connection form", () => {
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -47,12 +48,8 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"Snowflake"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", "Snowflake");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("Snowflake");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "Snowflake");
cy.get("[data-cy='data-source-snowflake']").click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -65,8 +62,6 @@ describe("Data sources", () => {
postgreSqlText.labelUserName
);
cy.get('[data-cy="label-account"]').verifyVisibleElement(
"have.text",
"Account"
@ -84,16 +79,12 @@ describe("Data sources", () => {
"have.text",
"Schema"
);
cy.get('[data-cy="label-warehouse"]').verifyVisibleElement(
"have.text",
"Warehouse"
);
cy.get('[data-cy="label-role"]').verifyVisibleElement(
"have.text",
"Role"
);
cy.get('[data-cy="label-role"]').verifyVisibleElement("have.text", "Role");
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
@ -121,9 +112,9 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
'A user name must be specified.'
"A user name must be specified."
);
});
@ -132,7 +123,7 @@ describe("Data sources", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
"cypress-snowflake"
`cypress-${data.lastName}-snowflake`
);
fillDataSourceTextField(
@ -156,23 +147,11 @@ describe("Data sources", () => {
"Enter database",
Cypress.env("snowflake_database")
);
fillDataSourceTextField(
"Schema",
"Enter schema",
"{del}"
);
fillDataSourceTextField("Schema", "Enter schema", "{del}");
fillDataSourceTextField(
"Warehouse",
"Enter warehouse",
"{del}"
);
fillDataSourceTextField("Warehouse", "Enter warehouse", "{del}");
fillDataSourceTextField(
"Role",
"Enter role",
"{del}"
);
fillDataSourceTextField("Role", "Enter role", "{del}");
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
@ -185,11 +164,11 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", "cypress-snowflake")
.find("button")
.invoke('show')
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-snowflake-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-snowflake`);
deleteDatasource(`cypress-${data.lastName}-snowflake`);
});
});

View file

@ -1,7 +1,10 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { deleteDatasource, closeDSModal } from "Support/utils/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -13,21 +16,19 @@ import {
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -47,12 +48,8 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"SQL Server"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", "SQL Server");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("SQL Server");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "SQL Server");
cy.get('[data-cy="data-source-sql server"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -115,9 +112,9 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
"have.text",
'Failed to connect to localhost:1433 - Could not connect (sequence)'
"Failed to connect to localhost:1433 - Could not connect (sequence)"
);
});
@ -126,7 +123,7 @@ describe("Data sources", () => {
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
"cypress-sqlserver"
`cypress-${data.lastName}-sqlserver`
);
fillDataSourceTextField(
@ -170,11 +167,10 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", "cypress-sqlserver")
.find("button")
.invoke("show")
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-sqlserver-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-sqlserver`);
deleteDatasource(`cypress-${data.lastName}-sqlserver`);
});
});

View file

@ -1,7 +1,10 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -13,21 +16,19 @@ import {
addWidgetsToAddUser,
} from "Support/utils/postgreSql";
const data = {};
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("Should verify elements on connection form", () => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.labelDataSources).should(
"have.text",
postgreSqlText.labelDataSources
);
cy.get(postgreSqlSelector.addDatasourceLink)
.should("have.text", postgreSqlText.labelAddDataSource)
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(commonSelectors.addNewDataSourceButton)
.verifyVisibleElement("have.text", commonText.addNewDataSourceButton)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
@ -47,12 +48,8 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
"TypeSense"
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", "TypeSense");
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("TypeSense");
cy.get("[data-cy*='data-source-']").eq(1).should("contain", "TypeSense");
cy.get('[data-cy="data-source-typesense"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
@ -102,34 +99,35 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
cy.get('[data-cy="connection-alert-text"]').should(
"have.text",
'Ensure that apiKey is set'
"Ensure that apiKey is set"
);
});
it.skip("Should verify the functionality of PostgreSQL connection form.", () => {
it("Should verify the functionality of PostgreSQL connection form.", () => {
selectDataSource("TypeSense");
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
"cypress-typesense"
`cypress-${data.lastName}-typesense`
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
Cypress.env("pg_host")
Cypress.env("typesense_host")
);
cy.get(".react-select__input-container").click().type(`HTTPS{enter}`);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
"5432"
Cypress.env("typesense_port")
);
fillDataSourceTextField(
"API Key",
"Enter API key",
"postgres"
Cypress.env("typesense_api_key")
);
//dropdown
cy.get(postgreSqlSelector.buttonTestConnection).click();
@ -143,10 +141,11 @@ describe("Data sources", () => {
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", "cypress-typesense")
.find("button")
.should("be.visible");
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.lastName}-typesense-button"]`
).verifyVisibleElement("have.text", `cypress-${data.lastName}-typesense`);
deleteDatasource(`cypress-${data.lastName}-typesense`);
});
});

View file

@ -0,0 +1,135 @@
import {
verifyMultipleComponentValuesFromInspector,
verifyComponentValueFromInspector,
} from "Support/utils/commonWidget";
import { verifyNodeData, openNode, verifyValue } from "Support/utils/inspector";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { addNewPage } from "Support/utils/multipage";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
import { multipageSelector } from "Selectors/multipage";
describe("Editor- Inspector", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
it("should verify the values of inspector", () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
verifyNodeData("queries", "Object", "0 entry ");
verifyNodeData("components", "Object", "0 entry ");
verifyNodeData("globals", "Object", "3 entries ");
verifyNodeData("variables", "Object", "0 entry ");
verifyNodeData("page", "Object", "4 entries ");
openNode("globals");
verifyNodeData("theme", "Object", "1 entry ");
verifyNodeData("urlparams", "Object", "0 entry ");
verifyNodeData("currentUser", "Object", "4 entries ");
openNode("theme");
verifyValue("name", "String", `"light"`);
openNode("currentUser");
verifyValue("email", "String", `"dev@tooljet.io"`);
verifyValue("firstName", "String", `"The"`);
verifyValue("lastName", "String", `"Developer"`);
verifyNodeData("groups", "Array", "2 items ");
openNode("groups");
verifyValue("0", "String", `"all_users"`);
verifyValue("1", "String", `"admin"`);
openNode("globals");
openNode("page");
verifyValue("handle", "String", `"home"`);
verifyValue("name", "String", `"Home"`);
cy.get(multipageSelector.sidebarPageButton).click();
addNewPage("test_page");
cy.dragAndDropWidget("Button", 100, 200);
selectEvent("On click", "Switch page");
cy.get('[data-cy="switch-page-label-and-input"] > .select-search')
.click()
.type("home{enter}");
cy.get('[data-cy="button-add-query-param"]').click();
addSupportCSAData("query-param-key", "key");
addSupportCSAData("query-param-value", "value");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Button", 100, 300);
selectEvent("On click", "Set variable");
addSupportCSAData("key", "globalVar");
addSupportCSAData("variable", "globalVar");
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Button", 100, 400);
selectEvent("On click", "Set page variable");
addSupportCSAData("key", "pageVar");
addSupportCSAData("variable", "pageVar");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.sidebarinspector).click();
openNode("variables");
verifyValue("globalVar", "String", `"globalVar"`);
openNode("page");
openNode("variables", 1);
verifyValue("pageVar", "String", `"pageVar"`);
verifyValue("handle", "String", `"test-page"`);
verifyValue("name", "String", `"test_page"`);
openNode("components");
verifyNodeData("button1", "Object", "6 entries ");
verifyNodeData("button2", "Object", "6 entries ");
verifyNodeData("button3", "Object", "6 entries ");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.sidebarinspector).click();
openNode("page");
verifyValue("handle", "String", `"home"`);
verifyValue("name", "String", `"Home"`);
openNode("globals");
verifyNodeData("urlparams", "Object", "1 entry ");
openNode("urlparams");
verifyValue("key", "String", `"value"`);
cy.get(`[data-cy="inspector-node-key"] > .mx-1`).realHover();
cy.get(".mx-1 > img").realClick();
cy.realPress("Escape");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq("{{globals.urlparams.key}}");
});
});
cy.get(".action-icons-group > .d-flex > :nth-child(2)").click();
cy.get(".list-group-item").click();
cy.realPress("Escape");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq(`"value"`);
});
});
cy.dragAndDropWidget("Button", 100, 300);
cy.get(commonWidgetSelector.sidebarinspector).click();
openNode("components");
cy.get(`[data-cy="inspector-node-button1"] > .mx-1`).realHover();
cy.get('[style="height: 13px; width: 13px;"] > img').click();
cy.notVisible(commonWidgetSelector.draggableWidget("button1"));
});
});

View file

@ -25,6 +25,11 @@ import {
verifyPropertiesGeneralAccordion,
verifyStylesGeneralAccordion,
} from "Support/utils/commonWidget";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
describe("Editor- Test Button widget", () => {
beforeEach(() => {
@ -335,4 +340,62 @@ describe("Editor- Test Button widget", () => {
cy.get(commonSelectors.viewerPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify csa", () => {
// cy.dragAndDropWidget(buttonText.defaultWidgetText);
selectEvent("On click", "Show alert");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Text input", 500, 50);
selectEvent("On change", "Control Component");
selectCSA("button1", "Set text", "500");
addSupportCSAData("Text", "{{components.textinput1.value");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 100);
selectEvent("On click", "Control Component");
selectCSA("button1", "Click");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 150);
selectEvent("On click", "Control Component");
selectCSA("button1", "Disable");
cy.get('[data-cy="Value-toggle-button"]').click();
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 200);
selectEvent("On click", "Control Component");
selectCSA("button1", "Visibility");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 250);
selectEvent("On click", "Control Component");
selectCSA("button1", "Loading");
cy.get('[data-cy="Value-toggle-button"]').click();
cy.get(commonWidgetSelector.draggableWidget("textinput1")).type("testBtn");
cy.wait(500);
cy.get(commonWidgetSelector.draggableWidget("button1")).should(
"have.text",
"testBtn"
);
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.verifyToastMessage(commonSelectors.toastMessage, "Hello world!");
cy.get(commonWidgetSelector.draggableWidget("button5")).click();
cy.get(
commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)
).should("have.class", "btn-loading");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(
commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)
).should("have.attr", "disabled");
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.get(
commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)
).should("not.be.visible");
});
});

View file

@ -313,6 +313,7 @@ describe("List view widget", () => {
cy.forceClickOnCanvas();
openEditorSidebar(data.widgetName);
verifyAndModifyParameter("Row height", "99");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
openEditorSidebar(data.widgetName);
cy.forceClickOnCanvas();

View file

@ -4,7 +4,6 @@ import { fake } from "Fixtures/fake";
import { commonWidgetText } from "Texts/common";
import { verifyControlComponentAction } from "Support/utils/button";
import { selectEvent } from "Support/utils/events";
import {
launchModal,
closeModal,
@ -25,7 +24,6 @@ import {
verifyAndModifyStylePickerFx,
verifyWidgetColorCss,
selectColourFromColourPicker,
verifyLoaderColor,
fillBoxShadowParams,
verifyBoxShadowCss,
verifyLayout,
@ -34,6 +32,11 @@ import {
verifyPropertiesGeneralAccordion,
verifyStylesGeneralAccordion,
} from "Support/utils/commonWidget";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
describe("Modal", () => {
beforeEach(() => {
@ -418,6 +421,28 @@ describe("Modal", () => {
.find(".form-check-input")
.click();
launchModal("modal1");
cy.wait(500);
cy.notVisible('[data-cy="modal-close-button"]');
});
it("should verify csa", () => {
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 200);
selectEvent("On click", "Control Component");
selectCSA("modal1", "open");
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get('[data-cy="modal-title"]').verifyVisibleElement(
"have.text",
"This title can be changed"
);
cy.get(".close-svg > path").click();
cy.dragAndDropWidget("Button", 500, 300, "Button", "[id*=canvas]:eq(2)");
selectEvent("On click", "Control Component");
selectCSA("modal1", "close");
// cy.realPress("Escape");
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.notVisible('[data-cy="modal-close-button"]');
});
});

View file

@ -32,6 +32,12 @@ import {
verifyWidgetText,
} from "Support/utils/commonWidget";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
describe("Multiselect widget", () => {
beforeEach(() => {
cy.appUILogin();
@ -342,4 +348,45 @@ describe("Multiselect widget", () => {
verifyBoxShadowCss(data.widgetName, data.colour, data.boxShadowParam);
});
it("should verify CSA", () => {
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Number input", 600, 50);
selectEvent("On change", "Control Component");
selectCSA("multiselect1", "Select Option", "1000");
addSupportCSAData("Option", "{{components.numberinput1.value");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Number input", 600, 150);
selectEvent("On change", "Control Component");
selectCSA("multiselect1", "Deselect Option", "1000");
addSupportCSAData("Option", "{{components.numberinput2.value");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Button", 600, 250);
selectEvent("On click", "Control Component");
selectCSA("Multiselect1", "Clear selections");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.waitForAutoSave();
cy.reload();
cy.wait(3000);
verifyMultipleComponentValuesFromInspector("multiselect1", [2, 3]);
cy.get(commonWidgetSelector.draggableWidget("numberinput1"))
.clear()
.type("1");
verifyMultiselectHeader(
"multiselect1",
multiselectText.labelAllItemsSelected
);
cy.get(commonWidgetSelector.draggableWidget("numberinput2"))
.clear()
.type("3");
verifyMultipleComponentValuesFromInspector("multiselect1", [2, 1]);
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
verifyMultiselectHeader("multiselect1", "Select...");
});
});

View file

@ -122,12 +122,14 @@ describe("Password Input", () => {
commonWidgetSelector.draggableWidget(data.widgetName),
data.customText
);
cy.get('[data-cy="real-canvas"]').click("topLeft", { force: true });
cy.get(
commonWidgetSelector.validationFeedbackMessage(data.widgetName)
).verifyVisibleElement(
"have.text",
commonWidgetText.maxLengthValidationError(data.maximumLength)
);
openEditorSidebar(data.widgetName);
verifyAndModifyParameter(
commonWidgetText.labelcustomValidadtion,
@ -135,9 +137,11 @@ describe("Password Input", () => {
);
cy.forceClickOnCanvas();
cy.get(commonWidgetSelector.draggableWidget(data.widgetName)).clear();
cy.get('[data-cy="real-canvas"]').click("topLeft", { force: true });
cy.get(
commonWidgetSelector.validationFeedbackMessage(data.widgetName)
).verifyVisibleElement("have.text", data.customText);
openEditorSidebar(data.widgetName);
cy.get(
commonWidgetSelector.accordion(commonWidgetText.accordionProperties)
@ -322,6 +326,7 @@ describe("Password Input", () => {
.invoke("attr", "placeholder")
.should("contain", data.customText);
cy.get('[data-cy="real-canvas"]').click("topLeft", { force: true });
cy.get(
commonWidgetSelector.validationFeedbackMessage(
passwordInputText.defaultWidgetName
@ -338,6 +343,7 @@ describe("Password Input", () => {
commonWidgetSelector.draggableWidget(commonWidgetText.text1)
).verifyVisibleElement("have.text", "t");
cy.forceClickOnCanvas();
cy.get('[data-cy="real-canvas"]').click("topLeft", { force: true });
cy.get(
commonWidgetSelector.validationFeedbackMessage(
passwordInputText.defaultWidgetName
@ -348,6 +354,7 @@ describe("Password Input", () => {
commonWidgetSelector.draggableWidget(passwordInputText.defaultWidgetName),
data.customText.toUpperCase()
);
cy.get('[data-cy="real-canvas"]').click("topLeft", { force: true });
cy.get(
commonWidgetSelector.validationFeedbackMessage(
passwordInputText.defaultWidgetName

View file

@ -23,6 +23,11 @@ import {
dataCsvAssertionHelper,
addFilter,
} from "Support/utils/table";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
import {
openAccordion,
verifyAndModifyParameter,
@ -937,5 +942,59 @@ describe("Table", () => {
]);
});
it("should verify table preview", () => {});
it("should verify table CSA", () => {
cy.get('[data-cy="column-id"]').click();
cy.get('[data-cy="make-editable-toggle-button"]').click();
cy.get(
'[data-cy="number-of-rows-per-page-input-field"]'
).clearAndTypeOnCodeMirror("{{2");
verifyAndModifyToggleFx("Highlight selected row", "{{false}}", true);
cy.get('[data-cy="real-canvas"]').click("topRight");
cy.dragAndDropWidget("Button", 870, 50);
selectEvent("On click", "Control Component");
selectCSA("table1", "Set page");
addSupportCSAData("Page", "{{2");
cy.get('[data-cy="real-canvas"]').click("topRight");
cy.dragAndDropWidget("Button", 870, 100);
selectEvent("On click", "Control Component");
selectCSA("table1", "Select row");
addSupportCSAData("Key", "name");
addSupportCSAData("Value", "Lisa");
cy.get('[data-cy="real-canvas"]').click("topRight");
cy.dragAndDropWidget("Button", 870, 150);
selectEvent("On click", "Control Component");
selectCSA("table1", "Deselect row");
cy.get('[data-cy="real-canvas"]').click("topRight");
cy.dragAndDropWidget("Button", 870, 200);
selectEvent("On click", "Control Component");
selectCSA("table1", "Discard Changes");
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get('[role="row"]').eq(2).should("have.class", "selected");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get('[role="row"]').eq(2).should("not.have.class", "selected");
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get('[data-cy*="-cell-1"] ').eq(1).should("have.text", "Jon");
cy.get('[data-cy="page-index-details"]').should("have.text", "2 of 2");
cy.get('[data-cy="3-cell-0"]')
.click()
.find("input")
.clear()
.type("test123");
cy.get('[data-cy*="-cell-0"]')
.eq(0)
.find("input")
.should("have.value", "test123");
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.get('[data-cy*="-cell-0"]').eq(0).should("have.text", "3");
});
});

View file

@ -0,0 +1,70 @@
import { fake } from "Fixtures/fake";
import { textInputText } from "Texts/textInput";
import { commonWidgetText, widgetValue, customValidation } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { buttonText } from "Texts/button";
import {
verifyControlComponentAction,
randomString,
} from "Support/utils/textInput";
import {
openAccordion,
verifyAndModifyParameter,
openEditorSidebar,
verifyAndModifyToggleFx,
addDefaultEventHandler,
verifyComponentValueFromInspector,
selectColourFromColourPicker,
verifyBoxShadowCss,
verifyLayout,
verifyTooltip,
editAndVerifyWidgetName,
verifyPropertiesGeneralAccordion,
verifyStylesGeneralAccordion,
randomNumber,
closeAccordions,
} from "Support/utils/commonWidget";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
describe("Text Input", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
cy.dragAndDropWidget("Text");
});
it("should verify CSA", () => {
const data = {};
data.customText = randomString(12);
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 200);
selectEvent("On click", "Control Component");
selectCSA("text1", "Visibility");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Text input", 500, 50);
selectEvent("On change", "Control Component");
selectCSA("text1", "Set text", "500");
addSupportCSAData("Text", "{{components.textinput1.value");
cy.get('[data-cy="real-canvas"]').click("topLeft", { force: true });
cy.clearAndType(
commonWidgetSelector.draggableWidget("textinput1"),
data.customText
);
cy.get(commonWidgetSelector.draggableWidget("text1")).verifyVisibleElement(
"have.text",
data.customText
);
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.draggableWidget("textinput1")).should(
"not.be.visible"
);
});
});

View file

@ -24,6 +24,11 @@ import {
randomNumber,
closeAccordions,
} from "Support/utils/commonWidget";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
describe("Text Input", () => {
beforeEach(() => {
@ -400,4 +405,75 @@ describe("Text Input", () => {
data.tooltipText
);
});
it("should verify CSA", () => {
const data = {};
data.customText = randomString(12);
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 200);
selectEvent("On click", "Control Component");
selectCSA("textinput1", "Visibility");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Text input", 500, 50);
selectEvent("On change", "Control Component");
selectCSA("textinput1", "Set text", "500");
addSupportCSAData("text", "{{components.textinput2.value");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 275);
selectEvent("On click", "Control Component");
selectCSA("textinput1", "Clear", "500");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 350);
selectEvent("On click", "Control Component");
selectCSA("textinput1", "Disable", "500");
cy.get('[data-cy="Value-toggle-button"]').click();
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 425);
selectEvent("On click", "Control Component");
selectCSA("textinput1", "Set blur", "500");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget(buttonText.defaultWidgetText, 500, 500);
selectEvent("On click", "Control Component");
selectCSA("textinput1", "Set focus");
cy.clearAndType(
commonWidgetSelector.draggableWidget("textinput2"),
data.customText
);
cy.get(
commonWidgetSelector.draggableWidget("textinput1")
).verifyVisibleElement("have.value", data.customText);
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get(
commonWidgetSelector.draggableWidget("textinput1")
).verifyVisibleElement("have.value", "");
cy.get(commonWidgetSelector.draggableWidget("button5")).click();
cy.realType(data.customText);
cy.get(
commonWidgetSelector.draggableWidget("textinput1")
).verifyVisibleElement("have.value", data.customText);
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.realType("not working");
cy.get(
commonWidgetSelector.draggableWidget("textinput1")
).verifyVisibleElement("have.value", data.customText);
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.draggableWidget("textinput1"))
.parent()
.should("have.attr", "data-disabled", "true");
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.draggableWidget("textinput1")).should(
"not.be.visible"
);
});
});

View file

@ -5,7 +5,7 @@ import { logout } from "Support/utils/common";
describe("Self host onboarding", () => {
beforeEach(() => {
cy.visit(Cypress.env("self_host"));
cy.visit('/setup');
});
it("verify elements on self host onboarding page", () => {
@ -89,7 +89,7 @@ describe("Self host onboarding", () => {
signup.commonElementsWorkspaceSetup();
cy.get(commonSelectors.onboardingPageHeader).verifyVisibleElement(
"have.text",
commonText.companyPageHeader("The developer")
commonText.companyPageHeader("The Developer")
);
cy.get(commonSelectors.companyNameInputField).should("be.visible");
cy.clearAndType(commonSelectors.companyNameInputField, "ToolJet");
@ -146,17 +146,21 @@ describe("Self host onboarding", () => {
.type("919876543210");
cy.get(commonSelectors.continueButton).click();
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
cy.get("body").then(($title) => {
if (!$title.text().includes("Enter your phone number")) {
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
logout();
cy.appUILogin();
logout();
cy.appUILogin();
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
}
});
});
});

View file

@ -40,18 +40,21 @@ describe("dashboard", () => {
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=", {
fixture: "intercept/emptyDashboard.json",
}).as("emptyDashboard");
cy.intercept("GET", "/api/folders?searchKey=",{"folders":[]}).as("folders");
cy.intercept("GET", "/api/folders?searchKey=", { folders: [] }).as(
"folders"
);
login();
cy.wait("@emptyDashboard");
cy.wait("@folders");
deleteDownloadsFolder();
// deleteDownloadsFolder();
});
it("should verify the elements on empty dashboard", () => {
cy.get(commonSelectors.homePageLogo).should("be.visible");
cy.get(
commonSelectors.workspaceName
).verifyVisibleElement("have.text", "My workspace");
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
);
cy.get(commonSelectors.workspaceName).click();
cy.get(commonSelectors.editRectangleIcon).should("be.visible");
cy.get(commonSelectors.appCreateButton).verifyVisibleElement(
@ -91,9 +94,7 @@ describe("dashboard", () => {
commonText.viewReadNotifications
);
cy.get(dashboardSelector.modeToggle).should("be.visible")
.click();
cy.get(dashboardSelector.modeToggle).should("be.visible").click();
cy.get(commonSelectors.mainWrapper)
.should("have.attr", "class")
.and("contain", "theme-dark");
@ -102,11 +103,11 @@ describe("dashboard", () => {
.should("have.attr", "class")
.and("contain", "bg-light-gray");
cy.get(commonSelectors.profileSettings).should("be.visible").click();
cy.get(profileSelector.profileLink).verifyVisibleElement(
"have.text",
profileText.profileLink
);
cy.get(commonSelectors.profileSettings).should("be.visible").click();
cy.get(profileSelector.profileLink).verifyVisibleElement(
"have.text",
profileText.profileLink
);
cy.get(commonSelectors.logoutLink).verifyVisibleElement(
"have.text",
commonText.logoutLink
@ -117,7 +118,10 @@ describe("dashboard", () => {
commonText.breadcrumbApplications
);
});
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement( "have.text",dashboardText.dashboardAppsHeaderLabel);
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement(
"have.text",
dashboardText.dashboardAppsHeaderLabel
);
cy.get(dashboardSelector.versionLabel).should("be.visible");
cy.get(dashboardSelector.emptyPageImage).should("be.visible");
@ -133,11 +137,13 @@ describe("dashboard", () => {
"have.text",
dashboardText.createAppButton
);
// cy.get(dashboardSelector.importAppButton).verifyVisibleElement(
// "have.text",
// dashboardText.importAppButton
// );
cy.get(dashboardSelector.importAppButton).should("be.visible");
cy.get(dashboardSelector.importAppButton)
.invoke("text")
.then((text) => {
expect(text.trim()).equal(dashboardText.importAppButton);
});
cy.get(dashboardSelector.appTemplateRow).should("be.visible");
});
@ -165,8 +171,9 @@ describe("dashboard", () => {
});
});
viewAppCardOptions(data.appName);
cy.get(commonSelectors.appCardOptions(commonText.changeIconOption)
viewAppCardOptions(data.appName);
cy.get(
commonSelectors.appCardOptions(commonText.changeIconOption)
).verifyVisibleElement("have.text", commonText.changeIconOption);
cy.get(
commonSelectors.appCardOptions(commonText.addToFolderOption)
@ -250,6 +257,7 @@ describe("dashboard", () => {
dashboardText.appClonedToast
);
cy.wait("@appEditor");
cy.wait(300);
cy.clearAndType(commonSelectors.appNameInput, data.cloneAppName);
cy.get(commonSelectors.editorPageLogo).click();
cy.wait("@appLibrary");
@ -367,16 +375,14 @@ describe("dashboard", () => {
viewFolderCardOptions(data.folderName);
cy.get(commonSelectors.folderCard).should("be.visible");
cy.get(commonSelectors.editFolderOption).verifyVisibleElement(
"have.text",
commonText.editFolderOption
);
cy.get(commonSelectors.deleteFolderOption).verifyVisibleElement(
"have.text",
commonText.deleteFolderOption
);
cy.get(
commonSelectors.editFolderOption(data.folderName)
).verifyVisibleElement("have.text", commonText.editFolderOption);
cy.get(
commonSelectors.deleteFolderOption(data.folderName)
).verifyVisibleElement("have.text", commonText.deleteFolderOption);
cy.get(commonSelectors.editFolderOption).click();
cy.get(commonSelectors.editFolderOption(data.folderName)).click();
verifyModal(
commonText.updateFolderTitle,
commonText.updateFolderButton,
@ -390,7 +396,7 @@ describe("dashboard", () => {
);
viewFolderCardOptions(data.folderName);
cy.get(commonSelectors.editFolderOption).click();
cy.get(commonSelectors.editFolderOption(data.folderName)).click();
cy.clearAndType(commonSelectors.folderNameInput, data.updatedFolderName);
cancelModal(commonText.cancelButton);
@ -399,7 +405,7 @@ describe("dashboard", () => {
);
viewFolderCardOptions(data.folderName);
cy.get(commonSelectors.editFolderOption).click();
cy.get(commonSelectors.editFolderOption(data.folderName)).click();
cy.clearAndType(commonSelectors.folderNameInput, data.updatedFolderName);
cy.get(
commonSelectors.buttonSelector(commonText.updateFolderButton)
@ -410,7 +416,7 @@ describe("dashboard", () => {
.and("be.visible");
viewFolderCardOptions(data.updatedFolderName);
cy.get(commonSelectors.deleteFolderOption).click();
cy.get(commonSelectors.deleteFolderOption(data.updatedFolderName)).click();
verifyConfirmationModal(commonText.folderDeleteModalMessage);
cancelModal(commonText.cancelButton);

View file

@ -7,6 +7,7 @@ import * as groups from "Support/utils/manageGroups";
import * as permissions from "Support/utils/userPermissions";
const groupName = fake.firstName.replaceAll("[^A-Za-z]", "");
const newGroupname = `New ${groupName}`;
describe("Manage Groups", () => {
before(() => {
@ -15,7 +16,16 @@ describe("Manage Groups", () => {
});
it("Should verify the elements and functionalities on manage groups page", () => {
common.navigateToManageGroups();
cy.get(commonSelectors.breadcrumbTitle).should(($el) => {
expect($el.contents().first().text().trim()).to.eq("Workspace settings");
});
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement(
"have.text",
" Groups"
);
groups.manageGroupsElements();
cy.get(groupsSelector.createNewGroupButton).click();
cy.clearAndType(groupsSelector.groupNameInput, groupsText.admin);
cy.get(groupsSelector.createGroupButton).click();
@ -24,10 +34,8 @@ describe("Manage Groups", () => {
groupsText.groupNameExistToast
);
cy.get(groupsSelector.cancelButton).click();
cy.get(groupsSelector.tableHeader).verifyVisibleElement(
"have.text",
groupsText.tableHeader
);
cy.get(groupsSelector.groupNameInput).should("not.exist");
cy.get(groupsSelector.createNewGroupButton).click();
cy.clearAndType(groupsSelector.groupNameInput, groupName);
cy.get(groupsSelector.createGroupButton).click();
@ -41,30 +49,72 @@ describe("Manage Groups", () => {
groupName
);
cy.get(groupsSelector.groupLink(groupName)).click();
cy.get(groupsSelector.groupPageTitle(groupName)).verifyVisibleElement(
"have.text",
groupName
);
cy.get(groupsSelector.updateGroupNameLink(groupName)).verifyVisibleElement(
"have.text",
groupsText.editGroupNameButton
);
cy.get(groupsSelector.deleteGroupLink(groupName)).verifyVisibleElement(
"have.text",
groupsText.deleteGroupButton
);
cy.get(groupsSelector.appsLink).verifyVisibleElement(
"have.text",
groupsText.appsLink
);
cy.get(groupsSelector.usersLink).verifyVisibleElement(
"have.text",
groupsText.usersLink
);
cy.get(groupsSelector.permissionsLink).verifyVisibleElement(
"have.text",
groupsText.permissionsLink
);
cy.get(groupsSelector.appsLink).click();
cy.get(groupsSelector.searchBox).should("be.visible");
cy.get(groupsSelector.selectAddButton(groupName)).verifyVisibleElement(
cy.get(groupsSelector.selectAddButton).verifyVisibleElement(
"have.text",
groupsText.addButton
);
cy.get(groupsSelector.nameTableHeader).verifyVisibleElement(
"have.text",
groupsText.nameTableHeader
groupsText.textAppName
);
cy.get(groupsSelector.permissionstableHedaer).verifyVisibleElement(
"have.text",
groupsText.permissionstableHedaer
);
cy.get("body").then(($title) => {
if ($title.text().includes(groupsText.helperTextNoAppsAdded)) {
cy.get(groupsSelector.helperTextNoAppsAdded).verifyVisibleElement(
"have.text",
groupsText.helperTextNoAppsAdded
);
cy.get(groupsSelector.helperTextPermissions).verifyVisibleElement(
"have.text",
groupsText.helperTextPermissions
);
}
});
cy.get(groupsSelector.searchBox).should("be.visible");
cy.get(groupsSelector.usersLink).click();
cy.get(groupsSelector.multiSelectSearch).should("be.visible");
cy.get(groupsSelector.mutiSelectAddButton(groupName)).verifyVisibleElement(
"have.text",
groupsText.addButton
);
cy.get(groupsSelector.nameTableHeader).verifyVisibleElement(
"have.text",
groupsText.nameTableHeader
groupsText.userNameTableHeader
);
cy.get(groupsSelector.emailTableHeader).verifyVisibleElement(
"have.text",
@ -90,21 +140,16 @@ describe("Manage Groups", () => {
commonSelectors.toastMessage,
groupsText.permissionUpdatedToast
);
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsCreateLabel).verifyVisibleElement(
"have.text",
groupsText.createLabel
);
cy.get(groupsSelector.appsCreateCheck).uncheck();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsDeleteCheck).should("be.visible").check();
cy.get(groupsSelector.appsDeleteLabel).verifyVisibleElement(
"have.text",
groupsText.deleteLabel
);
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsDeleteCheck).uncheck();
cy.get(groupsSelector.resourcesFolders).verifyVisibleElement(
@ -129,11 +174,39 @@ describe("Manage Groups", () => {
);
cy.get(groupsSelector.workspaceVarCheckbox).uncheck();
cy.contains("td", groupName)
.parent()
.within(() => {
cy.get("td a").contains("Delete").click();
});
cy.get(groupsSelector.updateGroupNameLink(groupName)).click();
cy.get(groupsSelector.updateGroupNameModalTitle).verifyVisibleElement(
"have.text",
groupsText.updateGroupNameModalTitle
);
cy.get(groupsSelector.groupNameInput).should("be.visible");
cy.get(groupsSelector.cancelButton).verifyVisibleElement(
"have.text",
groupsText.cancelButton
);
cy.get(groupsSelector.createGroupButton).verifyVisibleElement(
"have.text",
groupsText.saveButton
);
cy.get(groupsSelector.cancelButton).click();
cy.get(groupsSelector.updateGroupNameLink(groupName)).click();
cy.clearAndType(groupsSelector.groupNameInput, newGroupname);
cy.get(groupsSelector.createGroupButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
groupsText.groupNameUpdateSucessToast
);
cy.get(groupsSelector.groupLink(newGroupname)).verifyVisibleElement(
"have.text",
newGroupname
);
cy.get(groupsSelector.groupLink(newGroupname)).click();
cy.get(groupsSelector.deleteGroupLink(newGroupname)).click();
cy.get(groupsSelector.confirmText).verifyVisibleElement(
"have.text",
groupsText.confirmText
@ -148,11 +221,7 @@ describe("Manage Groups", () => {
);
cy.get(commonSelectors.buttonSelector("Cancel")).click();
cy.contains("td", groupName)
.parent()
.within(() => {
cy.get("td a").contains("Delete").click();
});
cy.get(groupsSelector.deleteGroupLink(newGroupname)).click();
cy.get(commonSelectors.buttonSelector("Yes")).click();
});
});

View file

@ -6,7 +6,6 @@ import * as SSO from "Support/utils/manageSSO";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
describe("Manage SSO for multi workspace", () => {
const data = {};
beforeEach(() => {
@ -20,7 +19,10 @@ describe("Manage SSO for multi workspace", () => {
commonText.breadcrumbworkspaceSettingTitle
);
});
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement( "have.text",ssoText.pagetitle);
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement(
"have.text",
ssoText.pagetitle
);
cy.get(ssoSelector.cardTitle).verifyVisibleElement(
"have.text",
@ -50,10 +52,19 @@ describe("Manage SSO for multi workspace", () => {
SSO.generalSettings();
cy.get(ssoSelector.alertText).verifyVisibleElement( "have.text",ssoText.alertText);
cy.get(ssoSelector.alertText).verifyVisibleElement(
"have.text",
ssoText.alertText
);
cy.get(ssoSelector.passwordEnableToggle).should("be.visible");
cy.get(ssoSelector.passwordLoginToggleLbale).verifyVisibleElement( "have.text",ssoText.passwordLoginToggleLbale);
cy.get(ssoSelector.disablePasswordHelperText).verifyVisibleElement( "have.text",ssoText.disablePasswordHelperText);
cy.get(ssoSelector.passwordLoginToggleLbale).verifyVisibleElement(
"have.text",
ssoText.passwordLoginToggleLbale
);
cy.get(ssoSelector.disablePasswordHelperText).verifyVisibleElement(
"have.text",
ssoText.disablePasswordHelperText
);
SSO.passwordPageElements();
});
@ -62,7 +73,9 @@ describe("Manage SSO for multi workspace", () => {
common.navigateToManageSSO();
cy.get(ssoSelector.google).should("be.visible").click();
cy.get(ssoSelector.cardTitle).verifyVisibleElement(
"have.text",ssoText.googleTitle)
"have.text",
ssoText.googleTitle
);
cy.get(ssoSelector.googleEnableToggle).should("be.visible");
cy.get(ssoSelector.clientIdLabel).verifyVisibleElement(
"have.text",
@ -89,15 +102,16 @@ describe("Manage SSO for multi workspace", () => {
);
});
it("Should verify Git SSO page elements", () => {
it("Should verify Git SSO page elements", () => {
common.navigateToManageSSO();
cy.get(ssoSelector.git).should("be.visible").click();
cy.get(ssoSelector.githubLabel).verifyVisibleElement(
"have.text",ssoText.gitTitle);
"have.text",
ssoText.gitTitle
);
cy.get(ssoSelector.hostNameLabel).verifyVisibleElement(
cy.get(ssoSelector.hostNameLabel).verifyVisibleElement(
"have.text",
ssoText.hostNameLabel
);

View file

@ -1,6 +1,6 @@
import { commonSelectors } from "Selectors/common"
import { commonSelectors } from "Selectors/common";
import { fake } from "Fixtures/fake";
import { usersText } from "Texts/manageUsers"
import { usersText } from "Texts/manageUsers";
import { usersSelector } from "Selectors/manageUsers";
import * as users from "Support/utils/manageUsers";
import * as common from "Support/utils/common";
@ -17,6 +17,11 @@ describe("Manage Users for multiple workspace", () => {
beforeEach(() => {
cy.appUILogin();
});
let invitationToken,
organizationToken,
workspaceId,
userId,
url = "";
it("Should verify the Manage users page", () => {
common.navigateToManageUsers();
users.manageUsersElements();
@ -26,13 +31,22 @@ describe("Manage Users for multiple workspace", () => {
cy.get(usersSelector.buttonAddUsers).click();
cy.get(usersSelector.buttonInviteUsers).click();
cy.get(usersSelector.fullNameError).verifyVisibleElement("have.text",usersText.errorTextFieldRequired);
cy.get(usersSelector.emailError).verifyVisibleElement("have.text",usersText.errorTextFieldRequired);
cy.get(usersSelector.fullNameError).verifyVisibleElement(
"have.text",
usersText.errorTextFieldRequired
);
cy.get(usersSelector.emailError).verifyVisibleElement(
"have.text",
usersText.errorTextFieldRequired
);
cy.clearAndType(commonSelectors.inputFieldFullName, data.firstName);
cy.get(commonSelectors.inputFieldEmailAddress).clear();
cy.get(usersSelector.buttonInviteUsers).click();
cy.get(usersSelector.emailError).verifyVisibleElement("have.text",usersText.errorTextFieldRequired);
cy.get(usersSelector.emailError).verifyVisibleElement(
"have.text",
usersText.errorTextFieldRequired
);
cy.get(commonSelectors.inputFieldFullName).clear();
cy.clearAndType(commonSelectors.inputFieldEmailAddress, data.email);
@ -49,8 +63,8 @@ describe("Manage Users for multiple workspace", () => {
);
cy.get(usersSelector.buttonInviteUsers).click();
cy.verifyToastMessage(
commonSelectors.newToastMessage,
cy.get(commonSelectors.newToastMessage).should(
"have.text",
usersText.exsitingEmail
);
});
@ -61,9 +75,9 @@ describe("Manage Users for multiple workspace", () => {
users.confirmInviteElements();
cy.clearAndType(commonSelectors.passwordInputField, "pass");
cy.get(commonSelectors.acceptInviteButton).should('be.disabled');
cy.get(commonSelectors.acceptInviteButton).should("be.disabled");
cy.clearAndType(commonSelectors.passwordInputField, usersText.password);
cy.get(commonSelectors.acceptInviteButton).should('not.be.disabled');
cy.get(commonSelectors.acceptInviteButton).should("not.be.disabled");
cy.get(commonSelectors.acceptInviteButton).click();
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
@ -82,10 +96,8 @@ describe("Manage Users for multiple workspace", () => {
.within(() => {
cy.get("td small").should("have.text", usersText.activeStatus);
});
});
it("Should verify the archive functionality", () => {
common.navigateToManageUsers();
@ -131,31 +143,46 @@ describe("Manage Users for multiple workspace", () => {
usersText.unarchivedToast
);
cy.window().then((win) => {
cy.stub(win, "prompt").returns(win.prompt).as("copyToClipboardPrompt");
});
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get(usersSelector.copyInvitationLink).click();
});
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.inviteCopiedToast
);
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select invitation_token from users where email='${data.email}';`,
}).then((resp) => {
invitationToken = resp.rows[0].invitation_token;
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get(usersSelector.userStatus, { timeout: 9000 }).should(
"have.text",
usersText.invitedStatus
);
});
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: "select id from organizations where name='My workspace';",
}).then((resp) => {
workspaceId = resp.rows[0].id;
cy.get("@copyToClipboardPrompt").then((prompt) => {
common.logout();
cy.visit(prompt.args[0][1]);
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select id from users where email='${data.email}';`,
}).then((resp) => {
userId = resp.rows[0].id;
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select invitation_token from organization_users where user_id='${userId}';`,
}).then((resp) => {
organizationToken = resp.rows[1].invitation_token;
url = `/invitations/${invitationToken}/workspaces/${organizationToken}?oid=${workspaceId}`;
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get(usersSelector.userStatus, { timeout: 9000 }).should(
"have.text",
usersText.invitedStatus
);
});
common.logout();
cy.wait(500);
cy.visit(url);
});
});
});
});
cy.get(usersSelector.acceptInvite).click();

View file

@ -2,7 +2,7 @@ import { commonSelectors } from "Selectors/common";
import { fake } from "Fixtures/fake";
import { usersText } from "Texts/manageUsers";
import * as common from "Support/utils/common";
import { dashboardText } from "Texts/dashboard";
import { dashboardText, emptyDashboardText } from "Texts/dashboard";
import { groupsSelector } from "Selectors/manageGroups";
import { groupsText } from "Texts/manageGroups";
import * as permissions from "Support/utils/userPermissions";
@ -25,23 +25,18 @@ describe("User permissions", () => {
});
it("Should verify the create new app permission", () => {
permissions.addNewUserSW(
data.firstName,
data.lastName,
data.email,
data.companyName
);
permissions.reset();
permissions.addNewUserMW(data.firstName, data.email);
cy.get("body").then(($title) => {
if ($title.text().includes(dashboardText.emptyPageDescription)) {
cy.get(commonSelectors.emptyAppCreateButton).click();
cy.get(commonSelectors.dashboardAppCreateButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.createAppPermissionToast
);
} else {
cy.contains(dashboardText.createAppButton).should("not.exist");
cy.log("The app is created by the admin");
}
});
common.logout();
@ -55,17 +50,19 @@ describe("User permissions", () => {
.within(() => {
cy.get("td small").should("have.text", usersText.activeStatus);
});
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=").as("homePage");
cy.get(commonSelectors.homePageLogo).click();
cy.wait("@homePage");
cy.createApp();
cy.renameApp(data.appName);
cy.get(commonSelectors.editorPageLogo).click();
cy.reload();
common.navigateToManageGroups();
cy.get(groupsSelector.groupLink("Admin")).click();
cy.get(groupsSelector.groupLink("All users")).click();
cy.get(groupsSelector.appSearchBox).click();
cy.get(groupsSelector.searchBoxOptions).contains(data.appName).click();
cy.get(groupsSelector.selectAddButton("all_users")).click();
cy.get(groupsSelector.selectAddButton).click();
cy.get("table").contains("td", data.appName);
cy.contains("td", data.appName)
.parent()
@ -84,8 +81,11 @@ describe("User permissions", () => {
.parent()
.within(() => {
cy.get(commonSelectors.appTitle(data.appName)).trigger("mouseover");
cy.get(commonSelectors.launchButton).should(
"have.class",
"tj-disabled-btn"
);
});
cy.get(commonSelectors.launchButton).should("exist").and("be.disabled");
permissions.adminLogin();
cy.contains("tr", data.appName)
@ -105,20 +105,32 @@ describe("User permissions", () => {
.within(() => {
cy.get(commonSelectors.appTitle(data.appName)).trigger("mouseover");
});
cy.get(commonSelectors.launchButton).should("exist").and("be.disabled");
cy.get(commonSelectors.launchButton).should(
"have.class",
"tj-disabled-btn"
);
cy.get(commonSelectors.editButton).should("exist").and("be.enabled");
cy.get(commonSelectors.workspaceName).click();
cy.contains("Untitled workspace").click();
cy.contains(data.appName).should("not.exist");
cy.get(commonSelectors.workspaceName).click();
cy.contains("My workspace").should("be.visible").click();
cy.wait(200);
});
it("Should verify the Create and Delete app permission", () => {
common.navigateToManageGroups();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsCreateCheck).check();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsDeleteCheck).check();
common.logout();
cy.login(data.email, usersText.password);
cy.get(commonSelectors.appCreateButton).should("exist");
cy.get(commonSelectors.appCardOptionsButton).first().click();
common.viewAppCardOptions(data.appName);
cy.contains("Delete app").should("exist");
permissions.adminLogin();
@ -127,13 +139,14 @@ describe("User permissions", () => {
common.logout();
cy.login(data.email, usersText.password);
cy.get(commonSelectors.appCardOptionsButton).first().click();
common.viewAppCardOptions(data.appName);
cy.contains("Delete app").should("not.exist");
cy.createApp();
cy.renameApp(data.appName);
cy.get(commonSelectors.editorPageLogo).click();
cy.get(commonSelectors.appCardOptionsButton).first().click();
cy.reload();
common.viewAppCardOptions(data.appName);
cy.contains("Delete app").should("exist");
cy.get(commonSelectors.appCardOptions(commonText.deleteAppOption)).click();
cy.get(commonSelectors.buttonSelector("Yes")).click();
@ -155,8 +168,6 @@ describe("User permissions", () => {
common.logout();
cy.login(data.email, usersText.password);
cy.contains("+ Create new").should("exist");
cy.get(commonSelectors.createNewFolderButton).click();
cy.clearAndType(commonSelectors.folderNameInput, data.folderName);
cy.get(commonSelectors.createFolderButton).click();
@ -165,9 +176,11 @@ describe("User permissions", () => {
cy.contains("div", data.folderName)
.parent()
.within(() => {
cy.get(commonSelectors.folderCardOptions).invoke("click");
cy.get(commonSelectors.folderCardOptions(data.folderName)).invoke(
"click"
);
});
cy.get(commonSelectors.deleteFolderOption).click();
cy.get(commonSelectors.deleteFolderOption(data.folderName)).click();
cy.get(commonSelectors.buttonSelector("Yes")).click();
permissions.adminLogin();
@ -176,13 +189,12 @@ describe("User permissions", () => {
common.logout();
cy.login(data.email, usersText.password);
cy.contains("+ Create new").should("not.exist");
permissions.adminLogin();
cy.contains("td", data.appName)
.parent()
.within(() => {
cy.get("td a").contains("Delete").click();
cy.get("td a").contains("Remove").click();
});
common.logout();

View file

@ -111,7 +111,13 @@ Cypress.Commands.add("createApp", (appName) => {
Cypress.Commands.add(
"dragAndDropWidget",
(widgetName, positionX = 190, positionY = 80, widgetName2 = widgetName) => {
(
widgetName,
positionX = 190,
positionY = 80,
widgetName2 = widgetName,
canvas = commonSelectors.canvas
) => {
const dataTransfer = new DataTransfer();
cy.clearAndType(commonSelectors.searchField, widgetName);
@ -120,7 +126,7 @@ Cypress.Commands.add(
{ dataTransfer },
{ force: true }
);
cy.get(commonSelectors.canvas).trigger("drop", positionX, positionY, {
cy.get(canvas).trigger("drop", positionX, positionY, {
dataTransfer,
force: true,
});

View file

@ -40,7 +40,7 @@ export const randomDateOrTime = (format = "DD/MM/YYYY") => {
let startDate = new Date(2018, 0, 1);
startDate = new Date(
startDate.getTime() +
Math.random() * (endDate.getTime() - startDate.getTime())
Math.random() * (endDate.getTime() - startDate.getTime())
);
return moment(startDate).format(format);
};
@ -59,7 +59,7 @@ export const createFolder = (folderName) => {
export const deleteFolder = (folderName) => {
viewFolderCardOptions(folderName);
cy.get(commonSelectors.deleteFolderOption).click();
cy.get(commonSelectors.deleteFolderOption(folderName)).click();
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
cy.wait("@folderDeleted");
cy.verifyToastMessage(
@ -78,12 +78,12 @@ export const navigateToAppEditor = (appName) => {
.trigger("mousehover")
.trigger("mouseenter")
.find(commonSelectors.editButton)
.click({force:true});
.click({ force: true });
//cy.wait("@appEditor");
};
export const viewAppCardOptions = (appName) => {
cy.contains("div", appName)
cy.contains("div", appName)
.parent()
.within(() => {
cy.get(commonSelectors.appCardOptionsButton).invoke("click");
@ -94,7 +94,7 @@ export const viewFolderCardOptions = (folderName) => {
cy.get(commonSelectors.folderListcard(folderName))
.parent()
.within(() => {
cy.get('[data-cy="folder-card-menu-icon"]').invoke('click');
cy.get(commonSelectors.folderCardOptions(folderName)).invoke("click");
});
};
@ -158,7 +158,7 @@ export const searchUser = (email) => {
};
export const createWorkspace = (workspaceName) => {
cy.get('[data-cy="workspace-name"]').click();
cy.get(commonSelectors.workspaceName).click();
cy.get(commonSelectors.addWorkspaceButton).click();
cy.clearAndType(commonSelectors.workspaceNameInput, workspaceName);
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=").as("homePage");

View file

@ -289,8 +289,7 @@ export const verifyLayout = (widgetName) => {
export const verifyPropertiesGeneralAccordion = (widgetName, tooltipText) => {
openEditorSidebar(widgetName);
openAccordion(commonWidgetText.accordionGenaral);
cy.intercept("PUT", "/api/apps/**").as("apps");
cy.wait("@apps");
cy.wait(3000);
addAndVerifyTooltip(
commonWidgetSelector.draggableWidget(widgetName),
tooltipText

View file

@ -35,13 +35,21 @@ export const modifyAndVerifyAppCardIcon = (appName) => {
viewAppCardOptions(appName);
cy.get(commonSelectors.appCardOptions(commonText.changeIconOption)).click();
cy.get(dashboardSelector.appIcon(randomIcon)).first().click();
cy.get(".modal-body")
.parent()
.within(() => {
cy.get(dashboardSelector.appIcon(randomIcon)).first().click();
});
cancelModal(commonText.cancelButton);
viewAppCardOptions(appName);
cy.get(commonSelectors.appCardOptions(commonText.changeIconOption)).click();
cy.get(dashboardSelector.appIcon(randomIcon)).first().click();
cy.get(".modal-body")
.parent()
.within(() => {
cy.get(dashboardSelector.appIcon(randomIcon)).first().click();
});
cy.get(dashboardSelector.changeButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,

View file

@ -1,5 +1,8 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { cyParamName } from "../../constants/selectors/common";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
export const verifyCouldnotConnectWithAlert = (dangerText) => {
cy.get(postgreSqlSelector.connectionFailedText, {
@ -7,25 +10,51 @@ export const verifyCouldnotConnectWithAlert = (dangerText) => {
}).verifyVisibleElement("have.text", postgreSqlText.couldNotConnect, {
timeout: 5000,
});
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL)
.should("be.visible")
.contains(dangerText);
};
export const resizeQueryPanel=(height='90')=>{
export const resizeQueryPanel = (height = "90") => {
cy.get('[class="query-pane"]').invoke("css", "height", `calc(${height}%)`);
}
};
export const query=(operation)=>{
cy.get(`[data-cy="query-${operation}-button"]`).click()
}
export const query = (operation) => {
cy.get(`[data-cy="query-${operation}-button"]`).click();
};
export const verifypreview=(type,data)=>{
cy.get(`[data-cy="preview-tab-${type}"]`).click()
cy.get(`[data-cy="preview-${type}-data-container"]`).verifyVisibleElement('contain.text', data)
}
export const verifypreview = (type, data) => {
cy.get(`[data-cy="preview-tab-${type}"]`).click();
cy.get(`[data-cy="preview-${type}-data-container"]`).verifyVisibleElement(
"contain.text",
data
);
};
export const addInput=(field,data)=>{
cy.get(`[data-cy="${field.toLowerCase()}-input-field"]`).clearAndTypeOnCodeMirror(data)
}
export const addInput = (field, data) => {
cy.get(
`[data-cy="${field.toLowerCase()}-input-field"]`
).clearAndTypeOnCodeMirror(data);
};
export const deleteDatasource = (datasourceName) => {
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.reload();
cy.get(`[data-cy="${cyParamName(datasourceName)}-button"]`)
.parent()
.within(() => {
cy.get(`[data-cy="${cyParamName(datasourceName)}-delete-button"]`).invoke(
"click"
);
});
cy.get('[data-cy="yes-button"]').click();
};
export const closeDSModal = () => {
cy.get("body").then(($body) => {
cy.wait(500);
if (
$body.find('[data-cy="button-close-ds-connection-modal"]> img').length > 0
) {
cy.get('[data-cy="button-close-ds-connection-modal"]').realClick();
closeDSModal();
}
});
};

View file

@ -185,10 +185,10 @@ export const createNewColumnAndVerify = (
createNewColumnText.defaultValueLabel
);
cy.clearAndType(createNewColumnSelectors.columnNameInputField, columnName);
cy.get(createNewColumnSelectors.dataTypeDropdown) .within(() => {
cy.get(createNewColumnSelectors.dataTypeDropdown).within(() => {
cy.contains(`Select data type`).click();
cy.contains(`[id*="react-select-"]`, columnDataType).click();
})
cy.contains(`[id*="react-select-"]`, columnDataType).click();
});
if (defaultValue) {
cy.clearAndType(
createNewColumnSelectors.defaultValueInputField,
@ -481,7 +481,7 @@ export const editRowAndVerify = (
.realClick();
cy.verifyToastMessage(
commonSelectors.toastMessage,
createNewRowText.rowCreatedSuccessfullyToast
editRowText.rowEditedSuccessfullyToast
);
verifyRowData(rowNumber, columnName, rowFieldData);
};

View file

@ -1,6 +1,6 @@
export const selectEvent = (event, action) => {
cy.get('[data-cy="add-event-handler"]').click()
cy.get('[data-cy="event-handler"]').eq(0).click()
cy.get('[data-cy="add-event-handler"]').click();
cy.get('[data-cy="event-handler"]').eq(0).click();
cy.get('[data-cy="event-selection"]')
.click()
.find("input")
@ -14,15 +14,21 @@ export const selectEvent = (event, action) => {
export const selectCSA = (
component,
componentAction,
dbounce = `{selectAll}{backspace}`
debounce = `{selectAll}{backspace}`
) => {
cy.get('[data-cy="action-options-component-selection-field"]')
.click()
.find("input")
.type(`{selectAll}{backspace}${component}`);
.type(`{selectAll}{backspace}${component}{enter}`);
cy.get('[data-cy="action-options-action-selection-field"]')
.click()
.find("input")
.type(`{selectAll}{backspace}${componentAction}`);
cy.get('[data-cy="-input-field"]').type(`{selectAll}{backspace}${debounce}`);
.type(`{selectAll}{backspace}${componentAction}{enter}`);
cy.get('[data-cy="-input-field"]').type(
`{selectAll}{backspace}${debounce}{enter}`
);
};
export const addSupportCSAData = (field, data) => {
cy.get(`[data-cy="${field}-input-field"]`).clearAndTypeOnCodeMirror(data);
};

View file

@ -0,0 +1,31 @@
export const verifyNodeData = (node, type, children) => {
cy.get(
`[data-cy="inspector-node-${node.toLowerCase()}"] > .node-length-color`
)
.realHover()
.verifyVisibleElement("have.text", `${children}`);
cy.get(
`[data-cy="inspector-node-${node.toLowerCase()}"] > .node-key`
).verifyVisibleElement("have.text", node);
cy.get(
`[data-cy="inspector-node-${node.toLowerCase()}"] > .node-type`
).verifyVisibleElement("have.text", type);
};
export const openNode = (node, index = 0) => {
cy.get(`[data-cy="inspector-node-${node.toLowerCase()}"] > .node-key`)
.eq(index)
.click();
};
export const verifyValue = (node, type, children) => {
cy.get(`[data-cy="inspector-node-${node.toLowerCase()}"] > .mx-2`)
.realHover()
.verifyVisibleElement("have.text", `${children}`);
cy.get(
`[data-cy="inspector-node-${node.toLowerCase()}"] > .node-key`
).verifyVisibleElement("have.text", node);
cy.get(
`[data-cy="inspector-node-${node.toLowerCase()}"] > .mx-1`
).verifyVisibleElement("have.text", type);
};

View file

@ -1,20 +1,9 @@
import { groupsSelector } from "Selectors/manageGroups";
import { groupsText } from "Texts/manageGroups";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
export const manageGroupsElements = () => {
cy.get(groupsSelector.pageTitle).verifyVisibleElement(
"have.text",
groupsText.pageTitle
);
cy.get(groupsSelector.createNewGroupButton).verifyVisibleElement(
"have.text",
groupsText.createNewGroupButton
);
cy.get(groupsSelector.tableHeader).verifyVisibleElement(
"have.text",
groupsText.tableHeader
);
cy.get(groupsSelector.groupLink("All users")).verifyVisibleElement(
"have.text",
groupsText.allUsers
@ -24,8 +13,69 @@ export const manageGroupsElements = () => {
groupsText.admin
);
cy.get(groupsSelector.groupLink("Admin")).click();
cy.get(groupsSelector.groupLink("All users")).click();
cy.get(groupsSelector.groupPageTitle("All Users")).verifyVisibleElement(
"have.text",
groupsText.allUsers
);
cy.get(groupsSelector.createNewGroupButton).verifyVisibleElement(
"have.text",
groupsText.createNewGroupButton
);
cy.get(groupsSelector.appsLink).verifyVisibleElement(
"have.text",
groupsText.appsLink
);
cy.get(groupsSelector.usersLink).verifyVisibleElement(
"have.text",
groupsText.usersLink
);
cy.get(groupsSelector.permissionsLink).verifyVisibleElement(
"have.text",
groupsText.permissionsLink
);
cy.get(groupsSelector.appsLink).click();
cy.get(groupsSelector.textDefaultGroup).verifyVisibleElement(
"have.text",
groupsText.textDefaultGroup
);
cy.get(groupsSelector.searchBox).should("be.visible");
cy.get(groupsSelector.selectAddButton).verifyVisibleElement(
"have.text",
groupsText.addButton
);
cy.get(groupsSelector.nameTableHeader).verifyVisibleElement(
"have.text",
groupsText.textAppName
);
cy.get(groupsSelector.permissionstableHedaer).verifyVisibleElement(
"have.text",
groupsText.permissionstableHedaer
);
cy.get("body").then(($title) => {
if ($title.text().includes(groupsText.helperTextNoAppsAdded)) {
cy.get(groupsSelector.helperTextNoAppsAdded).verifyVisibleElement(
"have.text",
groupsText.helperTextNoAppsAdded
);
cy.get(groupsSelector.helperTextPermissions).verifyVisibleElement(
"have.text",
groupsText.helperTextPermissions
);
}
});
cy.get(groupsSelector.createNewGroupButton).should("be.visible").click();
cy.get(groupsSelector.cardTitle).verifyVisibleElement(
cy.get(groupsSelector.addNewGroupModalTitle).verifyVisibleElement(
"have.text",
groupsText.cardTitle
);
@ -40,23 +90,15 @@ export const manageGroupsElements = () => {
);
cy.get(groupsSelector.cancelButton).click();
cy.get(groupsSelector.searchBox).should("be.visible");
cy.get(groupsSelector.selectAddButton("all_users")).verifyVisibleElement(
"have.text",
groupsText.addButton
);
cy.get(groupsSelector.nameTableHeader).verifyVisibleElement(
"have.text",
groupsText.nameTableHeader
);
cy.get(groupsSelector.permissionstableHedaer).verifyVisibleElement(
"have.text",
groupsText.permissionstableHedaer
);
cy.get(groupsSelector.usersLink).click();
cy.get(groupsSelector.helperTextAllUsersIncluded).verifyVisibleElement(
"have.text",
groupsText.helperTextAllUsersIncluded
);
cy.get(groupsSelector.nameTableHeader).verifyVisibleElement(
"have.text",
groupsText.nameTableHeader
groupsText.userNameTableHeader
);
cy.get(groupsSelector.emailTableHeader).verifyVisibleElement(
"have.text",
@ -116,21 +158,52 @@ export const manageGroupsElements = () => {
);
cy.get(groupsSelector.workspaceVarCheckbox).uncheck();
cy.get(groupsSelector.groupLink("Admin")).click();
cy.get(groupsSelector.groupLink("All users")).click();
cy.get(groupsSelector.groupLink("Admin")).click();
cy.get(groupsSelector.groupLink("Admin")).verifyVisibleElement(
"have.text",
groupsText.admin
);
cy.get(groupsSelector.appsLink).click();
cy.get(groupsSelector.textDefaultGroup).verifyVisibleElement(
"have.text",
groupsText.textDefaultGroup
);
cy.get(groupsSelector.nameTableHeader).verifyVisibleElement(
"have.text",
groupsText.textAppName
);
cy.get(groupsSelector.permissionstableHedaer).verifyVisibleElement(
"have.text",
groupsText.permissionstableHedaer
);
cy.get("body").then(($title) => {
if ($title.text().includes(groupsText.helperTextNoAppsAdded)) {
cy.get(groupsSelector.helperTextNoAppsAdded).verifyVisibleElement(
"have.text",
groupsText.helperTextNoAppsAdded
);
cy.get(groupsSelector.helperTextPermissions).verifyVisibleElement(
"have.text",
groupsText.helperTextPermissions
);
}
});
cy.get(groupsSelector.usersLink).click();
cy.get(groupsSelector.multiSelectSearch).should("be.visible");
cy.get(groupsSelector.mutiSelectAddButton("Admin")).verifyVisibleElement(
"have.text",
groupsText.addButton
groupsText.addUsersButton
);
cy.get(groupsSelector.nameTableHeader).verifyVisibleElement(
"have.text",
groupsText.nameTableHeader
groupsText.userNameTableHeader
);
cy.get(groupsSelector.emailTableHeader).verifyVisibleElement(
"have.text",

View file

@ -183,9 +183,7 @@ export const passwordPageElements = () => {
commonSelectors.toastMessage,
ssoText.passwordEnabledToast
);
} else {
cy.get(ssoSelector.passwordEnableToggle).check();
cy.verifyToastMessage(
commonSelectors.toastMessage,

View file

@ -1,6 +1,6 @@
import { path } from "Texts/common";
import { commonSelectors } from "Selectors/common"
import { usersText } from "Texts/manageUsers"
import { commonSelectors } from "Selectors/common";
import { usersText } from "Texts/manageUsers";
import { usersSelector } from "Selectors/manageUsers";
import { ssoSelector } from "Selectors/manageSSO";
import { ssoText } from "Texts/manageSSO";
@ -8,13 +8,15 @@ import * as common from "Support/utils/common";
import { commonText } from "Texts/common";
export const manageUsersElements = () => {
cy.get(commonSelectors.breadcrumbTitle).should(($el) => {
expect($el.contents().first().text().trim()).to.eq(
commonText.breadcrumbworkspaceSettingTitle
);
});
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement( "have.text",usersText.breadcrumbUsersPageTitle);
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement(
"have.text",
usersText.breadcrumbUsersPageTitle
);
for (const element in usersSelector.usersElements) {
cy.get(usersSelector.usersElements[element]).verifyVisibleElement(
@ -23,11 +25,9 @@ export const manageUsersElements = () => {
);
}
cy.get(usersSelector.usersPageTitle).should(($el) => {
expect($el.contents().last().text().trim()).to.eq(
usersText.usersPageTitle
);
expect($el.contents().last().text().trim()).to.eq(usersText.usersPageTitle);
});
cy.get(commonSelectors.inputUserSearch).should("be.visible")
cy.get(commonSelectors.inputUserSearch).should("be.visible");
common.searchUser(usersText.adminUserEmail);
cy.contains("td", usersText.adminUserEmail)
.parent()
@ -55,45 +55,82 @@ export const manageUsersElements = () => {
.verifyVisibleElement("have.text", usersText.buttonAddUsers)
.click();
cy.get(usersSelector.buttonInviteWithEmail).verifyVisibleElement( "have.text",usersText.buttonInviteWithEmail);
cy.get(usersSelector.buttonUploadCsvFile).verifyVisibleElement("have.text",usersText.buttonUploadCsvFile);
cy.get(usersSelector.addUsersCardTitle).verifyVisibleElement("have.text",usersText.addUsersCardTitle);
cy.get(commonSelectors.labelFullNameInput).verifyVisibleElement("have.text",commonText.labelFullNameInput);
cy.get(usersSelector.buttonInviteWithEmail).verifyVisibleElement(
"have.text",
usersText.buttonInviteWithEmail
);
cy.get(usersSelector.buttonUploadCsvFile).verifyVisibleElement(
"have.text",
usersText.buttonUploadCsvFile
);
cy.get(usersSelector.addUsersCardTitle).verifyVisibleElement(
"have.text",
usersText.addUsersCardTitle
);
cy.get(commonSelectors.labelFullNameInput).verifyVisibleElement(
"have.text",
commonText.labelFullNameInput
);
cy.get(commonSelectors.inputFieldFullName).should("be.visible");
cy.get(commonSelectors.labelEmailInput).verifyVisibleElement("have.text",commonText.labelEmailInput);
cy.get(commonSelectors.labelEmailInput).verifyVisibleElement(
"have.text",
commonText.labelEmailInput
);
cy.get(commonSelectors.inputFieldEmailAddress).should("be.visible");
cy.get(commonSelectors.cancelButton).verifyVisibleElement("have.text",usersText.cancelButton);
cy.get(commonSelectors.cancelButton).verifyVisibleElement(
"have.text",
usersText.cancelButton
);
cy.get(usersSelector.buttonInviteUsers).verifyVisibleElement(
"have.text",
usersText.buttonInviteUsers
);
cy.get(commonSelectors.cancelButton).click();
cy.get(usersSelector.addUsersCardTitle).should("not.exist")
cy.get(usersSelector.addUsersCardTitle).should("not.exist");
cy.get(usersSelector.buttonAddUsers).click();
cy.get(commonSelectors.closeButton).click();
cy.get(usersSelector.addUsersCardTitle).should("not.exist")
cy.get(usersSelector.addUsersCardTitle).should("not.exist");
cy.get(usersSelector.buttonAddUsers).click();
cy.get(usersSelector.addUsersCardTitle).verifyVisibleElement("have.text", usersText.addUsersCardTitle);
cy.get(usersSelector.addUsersCardTitle).verifyVisibleElement(
"have.text",
usersText.addUsersCardTitle
);
cy.get(usersSelector.buttonUploadCsvFile).click();
cy.get(usersSelector.helperTextBulkUpload).verifyVisibleElement("have.text", usersText.helperTextBulkUpload);
cy.get(usersSelector.buttonDownloadTemplate).verifyVisibleElement("have.text", usersText.buttonDownloadTemplate);
cy.get(usersSelector.iconBulkUpload).should("be.visible")
cy.get(usersSelector.helperTextSelectFile).verifyVisibleElement("have.text", usersText.helperTextSelectFile);
cy.get(usersSelector.helperTextDropFile).verifyVisibleElement("have.text", usersText.helperTextDropFile);
cy.get(usersSelector.inputFieldBulkUpload).should("exist")
cy.get(usersSelector.buttonUploadUsers).verifyVisibleElement("have.text", usersText.buttonUploadUsers);
cy.get(usersSelector.helperTextBulkUpload).verifyVisibleElement(
"have.text",
usersText.helperTextBulkUpload
);
cy.get(usersSelector.buttonDownloadTemplate).verifyVisibleElement(
"have.text",
usersText.buttonDownloadTemplate
);
cy.get(usersSelector.iconBulkUpload).should("be.visible");
cy.get(usersSelector.helperTextSelectFile).verifyVisibleElement(
"have.text",
usersText.helperTextSelectFile
);
cy.get(usersSelector.helperTextDropFile).verifyVisibleElement(
"have.text",
usersText.helperTextDropFile
);
cy.get(usersSelector.inputFieldBulkUpload).should("exist");
cy.get(usersSelector.buttonUploadUsers).verifyVisibleElement(
"have.text",
usersText.buttonUploadUsers
);
};
export const inviteUser = (firstName, email) => {
let invitationToken,
organizationToken,
workspaceId,
userId,
url = "";
cy.get(usersSelector.buttonAddUsers).click();
cy.clearAndType(commonSelectors.inputFieldFullName, firstName);
cy.clearAndType(commonSelectors.inputFieldEmailAddress, email);
@ -103,22 +140,37 @@ export const inviteUser = (firstName, email) => {
commonSelectors.toastMessage,
usersText.userCreatedToast
);
cy.window().then((win) => {
cy.stub(win, "prompt").returns(win.prompt).as("copyToClipboardPrompt");
});
common.searchUser(email);
cy.contains("td", email)
.parent()
.within(() => {
cy.get(usersSelector.copyInvitationLink).click();
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select invitation_token from users where email='${email}';`,
}).then((resp) => {
invitationToken = resp.rows[0].invitation_token;
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: "select id from organizations where name='My workspace';",
}).then((resp) => {
workspaceId = resp.rows[0].id;
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select id from users where email='${email}';`,
}).then((resp) => {
userId = resp.rows[0].id;
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select invitation_token from organization_users where user_id='${userId}';`,
}).then((resp) => {
organizationToken = resp.rows[1].invitation_token;
url = `/invitations/${invitationToken}/workspaces/${organizationToken}?oid=${workspaceId}`;
common.logout();
cy.wait(500);
cy.visit(url);
});
});
});
cy.verifyToastMessage(
commonSelectors.toastMessage,
usersText.inviteCopiedToast
);
cy.get("@copyToClipboardPrompt").then((prompt) => {
common.logout();
cy.visit(prompt.args[0][1]);
});
};
@ -161,10 +213,9 @@ export const confirmInviteElements = () => {
commonText.passwordLabel
);
cy.get(commonSelectors.passwordInputField).should("be.visible");
cy.get(commonSelectors.acceptInviteButton).verifyVisibleElement(
"have.text",
commonText.acceptInviteButton
).should('be.disabled');
cy.get(commonSelectors.acceptInviteButton)
.verifyVisibleElement("have.text", commonText.acceptInviteButton)
.should("be.disabled");
cy.get(commonSelectors.signUpTermsHelperText).should(($el) => {
expect($el.contents().first().text().trim()).to.eq(
@ -180,21 +231,19 @@ export const confirmInviteElements = () => {
.and("have.attr", "href")
.and("equal", "https://www.tooljet.com/privacy");
cy.get("body").then(($el) => {
if ($el.text().includes("Google")) {
cy.get(ssoSelector.googleSSOText).verifyVisibleElement(
"have.text",
ssoText.googleSignUpText
);
cy.get(ssoSelector.gitSSOText).verifyVisibleElement(
"have.text",
ssoText.gitSignUpText
);
cy.get(commonSelectors.onboardingSeperator).should('be.visible')
}
});
cy.get("body").then(($el) => {
if ($el.text().includes("Google")) {
cy.get(ssoSelector.googleSSOText).verifyVisibleElement(
"have.text",
ssoText.googleSignUpText
);
cy.get(ssoSelector.gitSSOText).verifyVisibleElement(
"have.text",
ssoText.gitSignUpText
);
cy.get(commonSelectors.onboardingSeperator).should("be.visible");
}
});
};
export const userStatus = (email) => {

View file

@ -7,6 +7,8 @@ import { commonWidgetText } from "Texts/common";
import { openAccordion, openEditorSidebar } from "Support/utils/commonWidget";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { closeDSModal} from "Support/utils/dataSource";
export const addQuery = (queryName, query, dbName) => {
cy.get(postgreSqlSelector.buttonAddNewQueries).click();
@ -44,8 +46,9 @@ export const addQueryOnGui = (queryName, query) => {
);
};
export const selectDataSource = (dataSource) => {
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.addDatasourceLink).click();
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal()
cy.get(commonSelectors.addNewDataSourceButton).click();
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(dataSource);
cy.get(`[data-cy='data-source-${dataSource.toLowerCase()}']`).click();
};

View file

@ -131,18 +131,9 @@ export const releasedVersionAndVerify = (currentVersion) => {
releasedVersionText.releasedToastMessage(currentVersion)
);
cy.forceClickOnCanvas();
cy.wait(2000);
verifyModal(
appVersionText.createNewVersion,
appVersionText.createNewVersion,
appVersionSelectors.versionNameInputField
);
cy.contains(releasedVersionText.releasedModalText).should("be.visible");
cy.wait(500);
closeModal(commonText.closeButton);
cy.get(appVersionSelectors.currentVersionField(currentVersion)).should(
"have.class",
"color-light-green"
cy.get(".released-version-popup-cover").verifyVisibleElement(
"have.text",
releasedVersionText.releasedAppText
);
};

21
dependabot.yml Normal file
View file

@ -0,0 +1,21 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/server"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/plugins"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/marketplace"
schedule:
interval: "daily"

View file

@ -7,13 +7,12 @@ Left-sidebar has the following options:
- **[Pages](#pages)**
- **[Inspector](#inspector)**
- **[Datasources Manager](#datasources-manager)**
- **[Debugger](#debugger)**
- **[Theme switch](#theme-switch)**
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/leftsidebar.png" alt="App Builder: Left-sidebar"/>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/newside.png" alt="App Builder: Left-sidebar"/>
</div>
@ -25,7 +24,7 @@ Check the detailed documentation for **[Pages](/docs/tutorial/pages)**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/pages.png" alt="App Builder: Left-sidebar"/>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/pages2.png" alt="App Builder: Left-sidebar"/>
</div>
@ -37,19 +36,7 @@ Check the detailed guide on **[using Inspector](/docs/how-to/use-inspector)**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/inspector.png" alt="App Builder: Left-sidebar"/>
</div>
## Datasources Manager
Datasources Manager is used to connect or remove the datasources.
Check the detailed **[Datasources documentation](/docs/data-sources/overview)**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/datasources.png" alt="App Builder: Left-sidebar"/>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/inspector2.png" alt="App Builder: Left-sidebar"/>
</div>
@ -59,7 +46,7 @@ The debugger captures errors that happens while running the queries. For example
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/debugger.png" alt="App Builder: Left-sidebar"/>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/newdebug.png" alt="App Builder: Left-sidebar"/>
</div>

View file

@ -9,9 +9,9 @@ ToolJet's App Builder allows you to build applications. ToolJet's app builder ha
- **[Toolbar](/docs/app-builder/toolbar)**: configure app settings
- **[Canvas](/docs/app-builder/canvas)**: Arrange the components to build the interface of app
- **[Left-sidebar](/docs/app-builder/left-sidebar)**: Add **[pages](/docs/tutorial/pages)**, **[datasources](/docs/data-sources/overview)**, **[inspect](/docs/how-to/use-inspector)** the components, queries or variables, and **[debug](#debugger)** the errors.
- **[Left-sidebar](/docs/app-builder/left-sidebar)**: Add **[pages](/docs/tutorial/pages)**, **[inspect](/docs/how-to/use-inspector)** the components, queries or variables, and **[debug](#debugger)** the errors.
- **[Components library](/docs/app-builder/components-library)**(right sidebar): Drag any component or modify the property or styling
- **[Query Panel](/docs/app-builder/query-panel)**: Create, edit or manage the queries
- **[Query Panel](/docs/app-builder/query-panel)**: Create, edit or manage the queries from the **[datasources](/docs/data-sources/overview)**
<div style={{textAlign: 'center'}}>

View file

@ -3,7 +3,7 @@ id: query-panel
title: Query Panel
---
The Query Panel is present at the bottom of the app-builder, this is where you create queries to interact with connected datasources. You can perform API requests, query **[databases](/docs/data-sources/overview)**, or **[transform](/docs/tutorial/transformations)** or manipulate data with **[JavaScript](/docs/data-sources/run-js)** & **[Python](/docs/data-sources/run-py)**.
The Query Panel is present at the bottom of the app-builder, this is where you create queries to interact with connected **local** and **global** datasources. You can perform API requests, query **[databases](/docs/data-sources/overview)**, or **[transform](/docs/tutorial/transformations)** or manipulate data with **[JavaScript](/docs/data-sources/run-js)** & **[Python](/docs/data-sources/run-py)**.
The Query Panel has two sections:
- **[Query Manager](#query-manager)** on the right that includes a list of all the created queries
@ -11,7 +11,7 @@ The Query Panel has two sections:
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/querypanel.png" alt="App Builder: Component library- right sidebar"/>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui/querypanel.png" alt="App Builder: Component library- right sidebar"/>
</div>
@ -35,7 +35,7 @@ Add button is used to add more queries in the application. When Add button is cl
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/add.png" alt="App Builder: Component library- right sidebar"/>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui/add.png" alt="App Builder: Component library- right sidebar"/>
</div>
@ -174,4 +174,15 @@ Learn more about [Event Handlers and Actions](/docs/widgets/overview#component-e
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/advanced.png" alt="App Builder: Component library- right sidebar"/>
</div>
### Change Datasource
If more than one datasources are connected of same type then you can change the datasource of the query from this dropdown.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui/switch.png" alt="App Builder: Component library- right sidebar"/>
</div>

View file

@ -35,7 +35,7 @@ To configure the app's global settings, click on the kebab menu(three vertical d
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/toolbar/globalset.png" alt="App Builder: Toolbar"/>
<img className="screenshot-full" src="/img/v2-beta/app-builder/toolbar/newglobalset.png" alt="App Builder: Toolbar"/>
</div>

View file

@ -0,0 +1,384 @@
---
id: creating-a-plugin
title: 'Marketplace: Creating plugins'
---
# Marketplace: Creating plugins
## What are plugins
ToolJets development has centered on extensibility, allowing developers to utilize plugins that expand their capabilities. Currently, these plugins are limited to connectors, including data source connectors like PostgreSQL, MySQL, Twilio, Stripe, and more. Using JavaScript/TypeScript, developers can develop plugins to enhance ToolJet's functionality and publish these plugins on the ToolJet Marketplace.
This guide will provide step-by-step instructions for creating ToolJet plugins using the `tooljet` CLI.
The `tooljet` CLI is a user-friendly command-line tool designed to simplify the plugin building process. As part of this guide, we will create a basic plugin for GitHub.
## Step 1: Creating a New Plugin - GitHub Plugin
The first step is to bootstrap a new plugin for the ToolJet marketplace. The plugin will authenticate users with a GitHub Personal Access Token and include fundamental operations such as fetching user details, repositories, issues, and pull requests.
If you have completed the **[Setup](/docs/contributing-guide/marketplace/marketplace-setup)** guide, you can begin developing the plugin using the `tooljet` CLI. To initiate plugin development, enter the following command in the terminal:
```bash
# create a new plugin
tooljet plugin create github
```
When prompted, enter the **plugin name** and select the **plugin type**, which is api in this case. Additionally, select **yes** when prompted to create a new plugin for the marketplace.
If your plugin is hosted on GitHub, please provide the **repository URL** when prompted. Otherwise, leave it blank.
When a plugin is created using the `ToolJet` CLI, an object is added to the **plugins.json** file in the **`ToolJet/server/src/assets/marketplace/`** directory. This object includes metadata about the plugin, such as its name, description, version, author, and other relevant details.
The plugins.json file serves as a registry of all available plugins for use in ToolJet. When the ToolJet server starts up, it reads the plugins.json file and loads all plugins that are listed in it.
:::info
It is important to note that the plugins.json file should not be manually edited, as it is automatically generated by the `ToolJet CLI`. Making changes to this file can result in issues with the proper functioning of the plugins in the system.
:::
All marketplace plugins are stored in the **`/marketplace`** directory of the ToolJet repository. You can find the GitHub plugin **[here](https://github.com/ToolJet/ToolJet/tree/develop/marketplace/plugins/github)**.
The structure of a typical ToolJet plugin directory appears as follows:
```bash
github/
package.json
lib/
icon.svg
index.ts
operations.json
manifest.json
```
In this structure, the file **manifest.json** contains information about the plugin's name, description, and other details. The file **operations.json** contains metadata about all the operations that the plugin supports. The main file, **index.ts**, creates a QueryService for the plugin, which handles queries, connection testing, caching, and more. The **icon.svg** file serves as the plugin's icon, while **package.json** is automatically generated by the CLI.
:::info
**Why do we need a manifest.json file or a operations.json file?**
The manifest.json file is used by a React component to create a dynamic UI for connection forms. It defines the schema of an API or data source, including its name, type, and any exposed variables, as well as options for authentication and other customizable properties. The properties section specifies the required fields and their types for connecting to the API or data source. By reading the manifest.json file, the React component generates the necessary UI components based on the schema, such as text inputs, dropdowns, checkboxes, and other elements.
On the other hand, the operations.json file contains a schema definition for a specific data source, like Github. It describes the available operations and their parameters that can be used to query the data source. A React component uses this schema to create queries in ToolJet applications, generating a UI that allows users to select the desired operation and provide the required parameters. The component uses the properties defined in the operations.json file to create various UI elements, such as dropdowns and input fields, and handle user interactions to create the final query. Once the user fills in the required parameters, the component uses them to generate a query that can be executed against the data source and return the results to the user.
Overall, *manifest.json* and *operations.json* files are essential for creating dynamic UI components in ToolJet applications. They define the schema for data sources and available operations, which React components then use to generate user-friendly UI elements. By utilizing these files, ToolJet enables users to easily connect to various APIs and data sources, perform queries, and retrieve data in an intuitive and efficient manner.
:::
## Step 2: Defining the manifest.json file
To construct the connection form, it's important to include the necessary options in the manifest.json file. Here's an example of how to do it:
```json
"properties": {
"credentials": {
"label": "Authentication",
"key": "auth_type",
"type": "dropdown-component-flip",
"description": "A single select dropdown to choose credentials",
"list": [
{
"value": "personal_access_token",
"name": "Use Personal Access Token"
}
]
},
"personal_access_token": {
"token": {
"label": "Token",
"key": "personal_token",
"type": "password",
"description": "Enter your personal access token",
"hint": "You can generate a personal access token from your Github account settings."
}
}
}
```
This manifest.json file includes information about authentication options, specifically a dropdown to choose a type of credentials and a field to enter a personal access token. The label, key, type, description, and hint properties are used to define the specific fields and their types required for connecting to the API or data source.
In this particular code, there are two main properties defined: **`credentials`** and **`personal_access_token`**.
The **`credentials`** property specifies the authentication method to be used. It contains several keys:
- **`label`**: a user-friendly label for the authentication method, set to "Authentication"
- **`key`**: a unique identifier for the authentication method, set to "auth_type"
- **`type`**: the type of the authentication method, set to "dropdown-component-flip"
- **`description`**: a description of the authentication method, set to "A single select dropdown to choose credentials"
- **`list`**: an array of objects representing the different authentication methods available. In this case, there is only one method available: a personal access token. The `value` key in the object is set to "personal_access_token" and the `name` key is set to "Use Personal Access Token".
The **`personal_access_token`** property specifies the details of the personal access token authentication method. It contains a `token` key, which specifies the actual personal access token to be used. The `token` key contains several keys:
- **`label`**: a user-friendly label for the personal access token, set to "Token"
- **`key`**: a unique identifier for the personal access token, set to "personal_token"
- **`type`**: the type of the personal access token, set to "password"
- **`description`**: a description of the personal access token, set to "Enter your personal access token"
- **`hint`**: a hint for the personal access token, set to "You can generate a personal access token from your Github account settings."
The available `type` options are:
However, based on the code you provided, the available **`type`** options are:
- **`password`**: used to input a secret value, such as a password or an access token.
- **`dropdown-component-flip`**: used to create a dropdown menu that flips its position relative to the component that triggers it.
- **`text`**: used to input a single line of text.
- **`textarea`**: used to input multiple lines of text.
- **`toggle`**: used to create a simple on/off switch.
- **`react-component-headers`**: used to display headers for React components.
- **`codehinter`**: is a specialized input field used for entering code and has additional functionality, such as resolving JavaScript code within double curly braces`{{}}`.
:::tip
The **manifest.json** file is utilized by the connection modal component, which appears to prompt users to enter their datasource credentials. Meanwhile, the **operations.json** file is used by the query manager when users generate a specific query for a connected datasource. **Both files utilize a similar schema**.
:::
## Step 3: Defining the operations.json file
```json
"properties": {
"operation": {
"label": "Operation",
"key": "operation",
"type": "dropdown-component-flip",
"description": "Single select dropdown for operation",
"list": [
{
"value": "get_user_info",
"name": "Get user info"
},
{
"value": "get_repo",
"name": "Get repository"
},
{
"value": "get_repo_issues",
"name": "Get repository issues"
},
{
"value": "get_repo_pull_requests",
"name": "Get repository pull requests"
}
]
},
"get_user_info": {
"username": {
"label": "Username",
"key": "username",
"type": "codehinter",
"lineNumbers": false,
"description": "Enter username",
"width": "320px",
"height": "36px",
"className": "codehinter-plugins",
"placeholder": "Enter username"
}
},
"get_repo": {
"owner": {
"label": "Owner",
"key": "owner",
"type": "codehinter",
"lineNumbers": false,
"description": "Enter owner name",
"width": "320px",
"height": "36px",
"className": "codehinter-plugins",
"placeholder": "developer"
},
"repo": {
"label": "Repository",
"key": "repo",
"type": "codehinter",
"lineNumbers": false,
"description": "Enter repository name",
"width": "320px",
"height": "36px",
"className": "codehinter-plugins",
"placeholder": "tooljet"
}
},
"get_repo_issues": {
"owner": {
"label": "Owner",
"key": "owner",
"type": "codehinter",
"lineNumbers": false,
"description": "Enter owner name",
"width": "320px",
"height": "36px",
"className": "codehinter-plugins",
"placeholder": "developer"
},
"repo": {
"label": "Repository",
"key": "repo",
"type": "codehinter",
"lineNumbers": false,
"description": "Enter repository name",
"width": "320px",
"height": "36px",
"className": "codehinter-plugins",
"placeholder": "tooljet"
},
"state": {
"label": "State",
"key": "state",
"className": "codehinter-plugins col-4",
"type": "dropdown",
"description": "Single select dropdown for choosing state",
"list": [
{
"value": "open",
"name": "Open"
},
{
"value": "closed",
"name": "Closed"
},
{
"value": "all",
"name": "All"
}
]
}
},
"get_repo_pull_requests": {
"owner": {
"label": "Owner",
"key": "owner",
"type": "codehinter",
"lineNumbers": false,
"description": "Enter owner name",
"width": "320px",
"height": "36px",
"className": "codehinter-plugins",
"placeholder": "developer"
},
"repo": {
"label": "Repository",
"key": "repo",
"type": "codehinter",
"lineNumbers": false,
"description": "Enter repository name",
"width": "320px",
"height": "36px",
"className": "codehinter-plugins",
"placeholder": "tooljet"
},
"state": {
"label": "State",
"key": "state",
"type": "dropdown",
"className": "codehinter-plugins col-4",
"description": "Single select dropdown for choosing state",
"list": [
{
"value": "open",
"name": "Open"
},
{
"value": "closed",
"name": "Closed"
},
{
"value": "all",
"name": "All"
}
]
}
}
}
```
The operations.json file specifies the available operations that can be executed on the data source. It provides details about the operation type, required fields to execute the operation, and the data type of each field. The label, key, type, description, and hint properties are used to define the specific fields and their types required to establish a connection with the API or data source.
## Step 4: Add the npm package of Gitub to the plugin dependencies
- Change directory to the plugin directory where the npm package needs to be installed and then install the package
```bash
# change directory to the plugin directory and install the npm package
npm i octokit --workspace=@tooljet-marketplace/github
```
:::info
Steps to install npm package to a plugin
```bash
npm i <npm-package-name> --workspace=<plugin-name-in-package-json>
```
The command `npm i <npm-package-name> --workspace=<plugin-name-in-package-json>` is used to install a specific npm package into a particular workspace of a multi-package repository.
The *--workspace* flag is used to specify the workspace where the package should be installed. In this case, we are installing the package in the *@tooljet-marketplace/github* workspace.
:::
## Step 5: Implement the query execution logic in index.ts
In index.ts, the query execution logic needs to be implemented for the Github plugin's QueryService. The QueryService is responsible for handling the process of running queries and receives information about the data source, including credentials, configurations, and query parameters.
For the Github data source, the sourceOptions will contain the necessary authentication credentials, like the personal access token, while the queryOptions will include the configurations and parameters specific to the query, like obtaining a list of repositories for a particular user.
Using this information, the QueryService will create and execute API requests against the Github API. The resulting data will be returned to the caller for further processing as needed.
Create a new file **query_operations.ts** in the **plugins/github/src** directory and add the following code to it.
```typescript
import { Octokit } from 'octokit'
import { QueryOptions } from './types'
export async function getUserInfo(octokit: Octokit, options: QueryOptions): Promise<object> {
const { data } = await octokit.request(
'GET /users/{username}',
{
username: options.username
}
);
return data;
}
export async function getRepo(octokit: Octokit, options: QueryOptions): Promise<object> {
const { data } = await octokit.request(
'GET /repos/{owner}/{repo}',
{
owner: options.owner,
repo: options.repo
}
);
return data;
}
export async function getRepoIssues(octokit: Octokit, options: QueryOptions): Promise<object> {
const { data } = await octokit.request(
'GET /repos/{owner}/{repo}/issues',
{
owner: options.owner,
repo: options.repo,
state: options.state || 'all'
}
);
return data;
}
export async function getRepoPullRequests(octokit: Octokit, options: QueryOptions): Promise<object> {
const { data } = await octokit.request(
'GET /repos/{owner}/{repo}/pulls',
{
owner: options.owner,
repo: options.repo,
state: options.state || 'all'
}
);
return data;
}
```
The query_operations.ts file comprises functions that will execute the queries and will be called by the QueryService in index.ts.
The GitHub class has three methods:
- **run**: This method executes a query and is invoked by passing sourceOptions and queryOptions as input, representing the source metadata and query configuration, respectively. The run method utilizes the octokit library to send API requests to the GitHub API and returns the query result in a QueryResult object.
- **testConnection**: When adding a new data source to a ToolJet application, the connection can be tested. The testConnection method is used to test the connection, and it takes in sourceOptions as input, which represents the source metadata. The method tests the connection by trying to fetch the authenticated user and returns a ConnectionTestResult object indicating whether the connection was successful.
:::note
Not all data sources may support testing connections. If it's not applicable for your data source, you can disable the test connection feature by adding "customTesting": true to your plugin's manifest.json.
:::
- **getConnection**: This method is a helper function that returns an authenticated octokit client, which is utilized to send requests to the GitHub API. It takes in sourceOptions as input, representing the source metadata, and returns an authenticated octokit client.
## Removing a plugin
To remove a plugin from the marketplace, you can simply remove the object entry of the plugin from the **plugins.json**(`ToolJet/server/src/assets/marketplace/plugins.json`) and then re-run the build commands.
## Publish a plugin
To release a plugin, submit a pull request on ToolJet's GitHub Repository after creating it. The ToolJet team will review the pull request, and if approved, the plugin will be included and published in the next release.

View file

@ -0,0 +1,65 @@
---
id: marketplace-setup
title: 'Marketplace: Development Setup'
---
The Marketplace offers custom plugins that can be installed in your ToolJet instance. This guide aims to assist you in creating a new plugin for the ToolJet marketplace.
## Requirements
- [Node.js](https://nodejs.org/en/download/) **(v18.3.0)**
- [npm](https://www.npmjs.com/get-npm) **(v8.11.0)**
## Getting started
### Step 1. Setup ToolJet locally
To obtain the ToolJet repository via git, use the command:
```bash
git clone https://github.com/ToolJet/ToolJet.git
```
Next, refer to the appropriate guide for your development environment to follow the Setup instructions:
- **[MacOS](/docs/contributing-guide/setup/macos)**
- **[Docker](/docs/contributing-guide/setup/docker)**
- **[Ubuntu](/docs/contributing-guide/setup/ubuntu)**
### Step 2. Enabling the marketplace for your instance
To enable the marketplace for your ToolJet instance, you need to specify the following environment variables in your **`.env`** file:
#### Marketplace feature enable
Use this environment variable to enable/disable the feature that allows users to use the marketplace.
| variable | value |
| -------------------------- | ----------------- |
| ENABLE_MARKETPLACE_FEATURE | `true` or `false` |
#### Enable Marketplace plugin developement mode
The use of this environment variable facilitates plugin development by enabling automatic builds whenever package changes occur, thus simplifying the development process. Moreover, it also incorporates a reload button that retrieves all the recent local modifications from the file system for installed plugins, making it a valuable feature for improving the overall development experience.
| variable | value |
| -------------------------- | ----------------- |
| ENABLE_MARKETPLACE_DEV_MODE | `true` or `false` |
Please note that the marketplace is not enabled by default. After updating the variable, restart your ToolJet instance.
For information on running ToolJet on your local machine, please refer to the instructions provided **[here](/docs/category/contributing-guide)**. You can access the marketplace by navigating to the **'/integrations'** route.
### Step 3: Installation of tooljet-cli
In order to manage plugins for the ToolJet marketplace, including creating, updating, and deleting, you will need to utilize **[tooljet-cli](https://www.npmjs.com/package/@tooljet/cli)**. This can be installed via npm by entering the following command:
```bash
npm install -g tooljet-cli
# Ensure the installation was successful
tooljet --version
```
Having completed the environment setup for Marketplace Developer mode, we can proceed to the next section and commence with [developing the first plugin](/docs/contributing-guide/marketplace/creating-a-plugin).

View file

@ -3,7 +3,9 @@ id: docker
title: Docker
---
# Docker
:::warning
The following guide is intended for contributors to set-up ToolJet locally. If you're interested in **self-hosting** ToolJet, please refer to the **[Setup](/docs/setup/)** section.
:::
Docker compose is the easiest way to setup ToolJet server and client locally.

View file

@ -3,7 +3,10 @@ id: macos
title: Mac OS
---
# Mac OS
:::warning
The following guide is intended for contributors to set-up ToolJet locally. If you're interested in **self-hosting** ToolJet, please refer to the **[Setup](/docs/setup/)** section.
:::
Follow these steps to setup and run ToolJet on macOS for development purposes. Open terminal and run the commands below. We recommend reading our guide on [architecture](/docs/contributing-guide/setup/architecture) of ToolJet before proceeding.
## Setting up

View file

@ -3,7 +3,10 @@ id: ubuntu
title: Ubuntu
---
# Ubuntu
:::warning
The following guide is intended for contributors to set-up ToolJet locally. If you're interested in **self-hosting** ToolJet, please refer to the **[Setup](/docs/setup/)** section.
:::
Follow these steps to setup and run ToolJet on Ubuntu. Open terminal and run the commands below.
## Setting up

View file

@ -60,7 +60,7 @@ In addition, violations of this code outside our spaces may affect a persons
- If violations occur, organizers will take any action they deem appropriate for the infraction, up to and including expulsion.
:::info
Portions derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/), [The Rust Code of Conduct](https://www.rust-lang.org/conduct.html) and [The Ada Initiative](http://adainitiative.org/2014/02/18/howto-design-a-code-of-conduct-for-your-community/) under a Creative Commons Attribution-ShareAlike license.
Portions derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/), [The Rust Code of Conduct](https://www.rust-lang.org/conduct.html) under a Creative Commons Attribution-ShareAlike license.
:::
---

View file

@ -1,226 +0,0 @@
---
id: creating-a-plugin
title: Creating Plugins
---
# Creating plugins for ToolJet
## What are plugins
ToolJet is built with extensibility in mind. Plugins allows developers to extend the functionalities of ToolJet using JavaScript. Plugins can only be connectors at this moment. For example, the data source connectors such as PostgreSQL, MySQL, Twilio, Stripe, etc are built as plugins.
In this guide, we will walk you through building plugins for ToolJet with the help of `tooljet` cli.
`tooljet` cli is a commandline tool built for building plugins easily. We will build a simple plugin for BigQuery in this guide.
### What does a plugin look like?
All the plugins live under the `/plugins` directory. The structure of a plugin looks like this:
```
my-awesome-plugin/
package.json
lib/
icon.svg
index.ts
operations.json
manifest.json
```
- manifest.json should include information such as the name of plugin, description, etc.
- operations.json should include the metadata of all the operations supported by the plugin.
- index.ts is the main file. It defines a `QueryService` for the plugin. The `QueryService` handles running of queries, testing connections, caching connections, etc.
- icon.svg is the icon for the plugin.
- package.json is auto generated by the cli.
## Getting Started
1. Install [tooljet-cli](https://www.npmjs.com/package/@tooljet/cli):
```bash
$ npm i -g @tooljet/cli
```
2. Bootstrap a new plugin using cli
```bash
$ tooljet plugin create bigquery
```
```bash
creating plugin... done
Plugin: bigquery created successfully
└─ plugins
└─ packages
└─ bigquery
```
3. Add the npm package of BigQuery to the plugin dependencies
```bash
$ tooljet plugin install @google-cloud/bigquery --plugin bigquery
```
4. Now the directory for our new plugin should looks something like below:
```bash
plugins/
package.json
packages/
bigquery/
__tests__
bigquery.test.js
package.json
lib/
icon.svg
index.ts
operations.json
manifest.json
```
5. Add data source config paramets to manifest.json
Our BigQuery plugin needs private key of a GCP service account to connect to BigQuery. Let's add `private_key` as a property for the data source.
```json
{
"$schema": "https://json-schema.org/",
"$id": "https://tooljet.io/BigQuery.schema.json",
"title": "BigQuery datasource",
"description": "A schema defining BigQuery datasource",
"type": "api",
"source": {
"name": "BigQuery",
"kind": "bigquery",
"exposedVariables": {
"isLoading": false,
"data": {},
"rawData": {}
},
"options": {
"private_key": { "encrypted": true }
}
},
"defaults": {
"private_key": { "value": "" }
},
"properties": {
"private_key": {
"label": "Private key",
"key": "private_key",
"type": "textarea",
"description": "Enter JSON private key for service account"
}
},
"required": ["private_key"]
}
```
6. Import npm package BigQuery to index.ts
```javascript
const { BigQuery } = require('@google-cloud/bigquery');
```
6. Edit index.ts to include the logic for creating a connection.
```javascript
async getConnection(sourceOptions: any, _options?: object): Promise<any> {
const privateKey = JSON.parse(sourceOptions['private_key']);
const client = new BigQuery({
projectId: privateKey['project_id'],
credentials: {
client_email: privateKey['client_email'],
private_key: privateKey['private_key'],
},
});
return client;
}
```
7. Edit index.ts to include the logic for testing connection.
When a new data source is being added to a ToolJet application, the connection can be tested.
:::info
NOTE: Every data source might not have a way to test connection. If not applicable for your data source, you can disable the test connection feature by adding `"customTesting": true,` to the `manifest.json` of your plugin.
:::
8. Add manifest entry for operations
In this example, let's add two operations for our BigQuery plugin.
- *List databases* - Lists all the databases.
- *Query database* - Query a specific database.
We need to make the entries to `operations.json`. The `operations.json` should look like this now:
```json
{
"$schema": "https://json-schema.org/",
"$id": "https://tooljet.io/dataqueries/Bigquery.schema.json",
"title": "Dynamodb datasource",
"description": "Operations for BigQuery plugin",
"type": "object",
"defaults": {},
"properties": {
"operation": {
"label": "Operation",
"key": "operation",
"type": "dropdown-component-flip",
"description": "Single select dropdown for operation",
"list": [
{
"value": "list_datasets",
"name": "List Datasets"
},
{
"value": "query",
"name": "Query"
}
]
},
"query": {
"query": {
"label": "Query",
"key": "query",
"type": "codehinter",
"description": "",
"height": "150px"
}
}
}
}
```
8. Handle the logic for running queries in `index.ts`
`QueryService` receives the metadata of the data source including the credentials and configs for connecting and parameters for the query that was run. In our example, `sourceOptions` will have the `private_key` of BigQuery datasource associated with the query. `queryOptions` will have the configs and parameters for the specific query. For example, `queryOption.operation` will give the id of current operation.
```javascript
export default class BigQueryQueryService implements QueryService {
async run(sourceOptions: any, queryOptions: any, _dataSourceId: string): Promise<QueryResult> {
const operation = queryOptions.operation;
const client = await this.getConnection(sourceOptions);
let result = {};
try {
switch (operation) {
case 'list_datasets':
result = await client.getDatasets();
break;
}
} catch (error) {
throw new QueryError('Query could not be completed', error.message, {});
}
return {
status: 'ok',
data: result,
};
}
}
```
9. Since it is a smiliar step for adding the logic for handling `query` operation, skipping it.
10. Test files are generated by the cli when a plugin is created. You can use `jest` for writing the tests.
Tests for a specific plugin can be run using the command `tooljet plugin test --bigquery`
13. The plugin is now ready!

View file

@ -1,11 +1,88 @@
---
id: grpc
title: gRPC
---
# grpc
<div className='badge badge--primary heading-badge'>Self-hosted only</div>
ToolJet can connect to GRPC databases to read and write data.
:::caution
only self-hosted deployments will have access to a gRPC datasource that is capable of handling unary requests and responses.
:::
- [Connection](#connection)
- [Getting Started](#querying-grpc)
- [Setup](#setup)
- [Querying gRPC](#querying-grpc)
## Connection
## Setup
## Querying GRPC
### Step 1: Upgrade ToolJet to the version 2.5 or above
Find instructions on how to do this in the setup guides located here: https://docs.tooljet.com/docs/setup/.
### Step 2: Add proto files
At the root, create a directory named "**protos**" and add a "**service.proto**" file inside it.
### Step 3: Mount Volumes
In the `docker-compose.yml` add
```bash
./protos:/app/protos
```
to the 2 volume sections for **plugins** and **server**
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/grpc/proto1.png" alt="gRPC: datasource" width='500' />
</div>
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/grpc/proto2.png" alt="gRPC: datasource" width='500'/>
</div>
### Step 4: Reboot the instance
```bash
docker-compose up -d
```
## Querying gRPC
After setting up your proto files, you should be able to establish a connection to gRPC by going to the [global datasource](/docs/data-sources/overview) page.
### Connect the gRPC datasource
ToolJet requires the following to connect to gRPC servers:
- **Server URL**
- **Authentication type** (None, Basic, Bearer, and API key)
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/grpc/connection.png" alt="gRPC: connection" />
</div>
Once you have added the gRPC from the global datasource page, you'll find it on the query panel of the application.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/grpc/grpcgds.png" alt="gRPC: connection" />
</div>
### Creating query
You can now query a particular RPC method of the added services.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/grpc/query.png" alt="gRPC: connection" />
</div>

View file

@ -19,35 +19,43 @@ Global datasources are available only on **ToolJet version 2.3.0 and above**.
## Connecting global datasources
1. From the ToolJet dashboard, go to the **global datasources page** from the left sidebar.
1. **Create a new app** from the dashboard, and Select the **Add new global datasource** option from the query panel.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/overview/global.png" alt="Datasources: Overview" />
<img className="screenshot-full" src="/img/datasource-reference/newui/overview/qpanel.png" alt="Datasources: Overview" />
</div>
Or you can directly go to the **Global Datasources** page from the left sidebar of the dashboard
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/newui/overview/global.png" alt="Datasources: Overview" />
</div>
2. Click on the **Add new datasource** button, a modal will pop-up with all the available global datasources.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/overview/popup.png" alt="Datasources: Overview" />
<img className="screenshot-full" src="/img/datasource-reference/newui/overview/popup.png" alt="Datasources: Overview" />
</div>
3. Select the datasource, enter the **Credentials** and **Save** the datasource.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/overview/connection.png" alt="Datasources: Overview" />
<img className="screenshot-full" src="/img/datasource-reference/newui/overview/connection.png" alt="Datasources: Overview" />
</div>
4. Now, go back to the dashboard, create a new app, and the datasource will be available on the query panel under **Global Datasources**. Added datasources will be available on any of the **existing** or the **new applications**.
4. Now, go back to the dashboard, create a new app, and the datasource will be available on the query panel under **Global Datasources**. Added datasources will now be available on either of the **existing** and the **new applications**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/overview/globalquery.png" alt="Datasources: Overview" />
<img className="screenshot-full" src="/img/datasource-reference/newui/overview/newquery1.png" alt="Datasources: Overview" />
</div>
5. You can now create queries of the connected global datasource. From the queries, you'll be able to switch to **different connections** of the same datasource if there are more than one connections created.
5. You can now create queries to the connected global datasource. From the queries, you'll be able to switch to **different connections** of the same datasource if there are more than one connections created.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/overview/switch.png" alt="Datasources: Overview" />
@ -90,7 +98,7 @@ By default, 4 datasources will be available on every app on ToolJet:
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/datasource-reference/overview/default.png" alt="Datasources: Overview" />
<img className="screenshot-full" src="/img/datasource-reference/newui/overview/defaultds.png" alt="Datasources: Overview" />
</div>

View file

@ -83,21 +83,21 @@ Before getting into the quickstart, Sign up and create your account on **[ToolJe
1. Navigate to **ToolJet DB Editor** from the left sidebar on the dashboard
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/11c.png" alt="Getting started: Quickstart" />
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/111c.png" alt="Getting started: Quickstart" />
</div>
2. Click on **Add Table** button, enter **Table name** and **Add columns** from the drawer that slides from the right.
2. Click on **Create New Table** button, enter **Table name** and **Add columns** from the drawer that slides from the right. Click on **Create** to add the table.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/table.png" alt="Getting started: Quickstart" />
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/prodtable.png" alt="Getting started: Quickstart" />
</div>
3. Once the table is created, click on the **Add new row** button to add the data to the table and click **Create**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/row.png" alt="Getting started: Quickstart" />
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/newrow1.png" alt="Getting started: Quickstart" />
</div>
@ -111,7 +111,7 @@ Learn more about the **[ToolJet Database here](/docs/tooljet-database)**
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/newapp.png" alt="Getting started: Quickstart" />
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/newapp1.png" alt="Getting started: Quickstart" />
</div>
@ -122,7 +122,7 @@ Learn more about the **[ToolJet Database here](/docs/tooljet-database)**
2. When you click on create new app the **App-builder** will open up. You can rename your application from `untitled` to **Support Tool** from the top left of app-builder.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/name_app.png" alt="Getting started: Quickstart" />
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/appbuilder2.png" alt="Getting started: Quickstart" />
</div>
@ -148,10 +148,10 @@ ToolJet application's User interface is constructed using Components like Tables
### Build queries and bind data to UI
1. We can add a new datasource from the **Datasource manager** on the left-sidebar of the app builder but since we are using **ToolJet Database** we don't need to add any external datasource. Go to the **Query Panel -> Run ToolJetDb Query**
1. We can add a new datasource from the **[Global datasources](/docs/data-sources/overview)** page from the dashboard but since we are using **ToolJet Database** we don't need to add any external datasource. Go to the **Query Panel and select ToolJet Database**
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/querypanel.png" alt="Getting started: Quickstart" />
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/tjdb2.png" alt="Getting started: Quickstart" />
</div>
@ -164,7 +164,7 @@ ToolJet application's User interface is constructed using Components like Tables
3. Click on **Create** to create the query and then click **Run** to trigger the query and get response. You can also check the query response by clicking **Preview** button without firing the query.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/query.png" alt="Getting started: Quickstart" />
<img className="screenshot-full" src="/img/v2-beta/getting_started/quickstart/listrowsq.png" alt="Getting started: Quickstart" />
</div>

View file

@ -1,120 +0,0 @@
---
id: marketplace
title: Marketplace
---
# ToolJet Marketplace
ToolJet marketplace for plugins will allow users to install the custom plugins (datasources) for their ToolJet instances. This will allow ToolJet users to build their own custom plugins according to their requirements and then easily connect them to ToolJet.
## Enabling the marketplace for your instance
Users must add the following environment variable to the [`.env`](/docs/setup/env-vars#marketplace-feature-enable--optional-) file to enable the marketplace feature:
```bash
ENABLE_MARKETPLACE_FEATURE=true
```
Once the marketplace feature is enabled, users can open the **Marketplace** page from the dropdown on the navbar of the dashboard. Users can also directly access the marketplace using the URL: `https://tooljet.yourcompany.com/integrations`
:::info
The user logged-in should be the **Administrator** to access the marketplace page.
:::
## Installing a plugin
When you [create a plugin](#creating-a-marketplace-plugin) using the [tooljet cli](https://www.npmjs.com/package/@tooljet/cli), an object is created in the **plugins.json** (`ToolJet/server/src/assets/marketplace/plugins.json`) file for that particular plugin.
Here's an example of an entry created for AWS S3 plugin:
```json
[
{
"name": "AWS S3 plugin",
"description": "Datasource plugin for AWS S3",
"version": "1.0.0",
"id": "s3",
"repo": "",
"author": "Tooljet",
"timestamp": "Mon, 31 Oct 2022 11:02:10 GMT"
}
]
```
Now to install the plugin to the marketplace, you'll have to install npm package to a plugin:
```bash
npm i <npm-package-name> --workspace=<plugin-name-in-package-json>
```
Finally, run the build commands:
```bash
npm install
npm run build --workspaces
```
Once done, you'll find the plugin on the marketplace page.
## Removing a plugin
To remove a plugin from the marketplace, you can simply remove the object entry of the plugin from the **plugins.json**(`ToolJet/server/src/assets/marketplace/plugins.json`) and then re-run the build commands.
## Using a plugin as datasource
The flow for installing and using a plugin as a datasource is really simple. The steps are:
- Go to the **Marketplace**
- Click the Marketplace link in the left sidebar to view all available plugins.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/marketplacemain.png" alt="Marketplace" />
</div>
- Click on the **Install** button of the plugin that you want to install
- Once installed, you can check the installed plugins from **Installed** on the left sidebar. You can also **remove** the plugins from the Installed section of the marketplace.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/installed.png" alt="Installed plugins" />
</div>
- Now, let's use the installed plugin as the datasource for an application. User will have to open the application, go to the **Add Datasource** button on the left sidebar of the app builder, and then select Plugins on the modal that pops-up. The Plugins section will include all the plugins installed via Marketplace. The next steps are same as connecting a datasource to the application.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/datasource.png" alt="Installed plugins as datasource" />
</div>
## Creating a marketplace plugin
The steps for creating a Marketplace plugin are similar to those for creating [plugins for ToolJet](/docs/contributing-guide/tutorials/creating-a-plugin) except that for a Marketplace plugin, the user will have to type `yes` when prompted `Is it a marketplace integration?` in the `tooljet command line`.
The steps to create a marketplace plugin are:
- Install [tooljet-cli](https://www.npmjs.com/package/@tooljet/cli):
```bash
npm i -g @tooljet/cli
```
- Bootstrap a new plugin using cli
```bash
tooljet plugin create bigquery
```
- On the CLI, you'll be prompted to enter a display name:
```bash
Enter plugin display name:
```
- In the next step, you'll be asked to choose a plugin type **database**, **api**, or **cloud-storage**
- Now choose if `Is it a marketplace integration?` by entering `y/N`
- Enter the repository URL if the plugin is hosted on GitHub or else just press enter to skip to the next step
- Once done, all the plugin files will be generated inside the marketplace directory
```bash
creating plugin... done
Plugin: bigquery created successfully
└─ marketplace
└─ plugin
└─ bigquery
```
:::info
For more information on **[creating plugin for ToolJet](/docs/contributing-guide/tutorials/creating-a-plugin)**, please see the documentation on creating plugins.
:::

View file

@ -0,0 +1,97 @@
---
id: marketplace-overview
title: 'Marketplace : Overview'
---
# Marketplace : Overview
With ToolJet Marketplace, ToolJet users can conveniently add custom plugins (datasources) to their workspaces. This feature enables users to create plugins that cater to their specific needs and integrate them seamlessly with ToolJet.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/overview/marketplace.png" alt="Marketplace" />
</div>
## Enabling the Marketplace
To **Enable** the marketplace feature, users need to add the following environment variable to their **[`.env`](/docs/setup/env-vars#marketplace)** file:
```bash
ENABLE_MARKETPLACE_FEATURE=true
```
Once the marketplace feature has been activated, a Marketplace icon will appear on the left-hand sidebar of the dashboard, providing users with access to the Marketplace.
When running ToolJet locally, ensure that all the plugins are available. Specifically, building the marketplace and then starting the server is mandatory.
:::info Note
The user logged-in should be the **Administrator** to access the marketplace page.
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/overview/icon.png" alt="Marketplace" />
</div>
## Installing a plugin
The Marketplace page will contain two tabs: **Installed** and **Marketplace**.
Under the **Marketplace** tab, you will see a list of all the available plugins that can be installed on the workspace. To install a plugin, click on the **Install** button on the plugin's card. Once the installation is complete, the status will change from Install to **Installed**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/overview/allplugins.png" alt="Marketplace" />
</div>
## Using Marketplace plugins
You can access any installed plugins by following these steps:
- Navigate to the **Global Datasources** Page.
- Click on the **Add new datasource** button.
- Open the **Plugins** tab in the modal that appears.
- From here, you can connect to any of the plugins that were installed from the Marketplace.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/overview/gdsplugin.png" alt="Marketplace" />
</div>
- After successfully connecting to a plugin, you can access it under the Global Datasource section when creating queries.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/overview/query.png" alt="Marketplace" />
</div>
## Removing a plugin
:::caution
If you remove a plugin, all the queries associated with it will be eliminated from all the applications.
:::
To remove a plugin, follow these steps:
- Go to the Marketplace page from the dashboard.
- Go to the **Installed** tab and click on the **Remove** button next to the plugin that you want to remove.
- By doing so, the plugin will be removed from the global datasource section, and no user will be able to establish a connection with it.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/overview/remove.png" alt="Marketplace" />
</div>
## Available Plugins
- **[GitHub](/docs/marketplace/plugins/marketplace-plugin-github)**
- **[OpenAI](/docs/marketplace/plugins/marketplace-plugin-openai)**
- **[Plivo](/docs/marketplace/plugins/marketplace-plugin-plivo)**
:::info For Plugin Developers
Refer to the **[Plugin Development guide](/docs/contributing-guide/marketplace/marketplace-setup)** to learn how to create plugins for the ToolJet Marketplace.
:::

View file

@ -0,0 +1,105 @@
---
id: marketplace-plugin-github
title: GitHub
---
ToolJet can connect to GitHub account to read and write data. In order for ToolJet to access and manipulate data on GitHub, a **GitHub Personal Access Toke**n is necessary to authenticate and interact with the GitHub API.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/plugins/github/githubadd.gif" alt="Marketplace: GitHub" />
</div>
:::note
Before following this guide, it is assumed that you have already completed the process of **[Using Marketplace plugins](/docs/marketplace/marketplace-overview#using-marketplace-plugins)**.
:::
## Connection
For connecting to GitHub, following credentials are required:
- **Personal Access Token**: Generate a Personal Access Token from your **[GitHub Account Settings](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)**
:::caution
If a Personal Access Token is not provided, the data from the private repositories will not be retrieved via the GitHub Plugin. However, the public repositories data can still be retrieved.
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/plugins/github/connection.png" alt="Marketplace: GitHub" />
</div>
## Supported queries
- **[Get user info](#get-user-info)**
- **[Get repository](#get-repository)**
- **[Get repository issues](#get-repository-issues)**
- **[Get repository pull requests](#get-repository-pull-requests)**
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/plugins/github/list.png" alt="Marketplace: GitHub" />
</div>
### Get user info
All the details regarding the user is retrieved by running this query.
#### Required parameters:
- **Username**: To obtain the details, the username of the user must be provided for this field. You can input the username of a GitHub organization or a user for this field.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/plugins/github/getuserinfo.png" alt="Marketplace: GitHub" />
</div>
### Get repository
All the details regarding the repository are retrieved by running this query.
#### Required parameters:
- **Owner**: The owner's name of the repository is required for this field. The owner can either be a GitHub organization or a user.
- **Repository**: Provide the name of the repository of which you want to retrieve the details.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/plugins/github/getrepo.png" alt="Marketplace: GitHub" />
</div>
### Get repository issues
Running this query will retrieve a list of issues from a repository. You can select whether to obtain All, Open, or Closed issues.
#### Required parameters:
- **Owner**: The owner's name of the repository is required for this field. The owner can either be a GitHub organization or a user.
- **Repository**: Provide the name of the repository of which you want to retrieve the issues.
- **State**: Choose the state of the issues that you would like to retrieve: All, Open, or Closed.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/plugins/github/getissues.png" alt="Marketplace: GitHub" />
</div>
### Get repository pull requests
Running this query will retrieve a list of pull requests from a repository. You can select whether to obtain All, Open, or Closed issues.
#### Required parameters:
- **Owner**: The owner's name of the repository is required for this field. The owner can either be a GitHub organization or a user.
- **Repository**: Provide the name of the repository of which you want to retrieve the pull requests.
- **State**: Choose the state of the pull requests that you would like to retrieve: All, Open, or Closed.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/marketplace/plugins/github/getpr.png" alt="Marketplace: GitHub" />
</div>

Some files were not shown because too many files have changed in this diff Show more