Merge pull request #5467 from ToolJet/release/2.1.0

Release/2.1.0
This commit is contained in:
Sherfin Shamsudeen 2023-02-02 16:46:23 +05:30 committed by GitHub
commit 053fca3473
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
205 changed files with 3534 additions and 694 deletions

View file

@ -70,4 +70,3 @@ SSO_DISABLE_SIGNUPS=
#ONBOARDING
ENABLE_ONBOARDING_QUESTIONS_FOR_ALL_SIGN_UPS=
ENABLE_TOOLJET_DB=

View file

@ -4,6 +4,12 @@ on:
release:
types: [published]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
version:
description: "RELEASE_VERSION"
jobs:
packer:
runs-on: ubuntu-latest
@ -13,7 +19,12 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Set env
- name: Setting tag
if: "${{ github.event.inputs.version != '' }}"
run: echo "RELEASE_VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Set evn
if: "${{ github.event.release }}"
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Configure AWS Credentials

View file

@ -1 +1 @@
2.0.4
2.1.0

View file

@ -117,7 +117,7 @@ You can use ToolJet cloud for a fully managed solution. If you want to self-host
## Community support
For general help using ToolJet, please refer to the official [documentation](https://docs.tooljet.com/docs/intro/). For additional help, you can use one of these channels to ask a question:
For general help using ToolJet, please refer to the official [documentation](https://docs.tooljet.com/docs/). For additional help, you can use one of these channels to ask a question:
- [Slack](https://join.slack.com/t/tooljet/shared_invite/zt-r2neyfcw-KD1COL6t2kgVTlTtAV5rtg) - Discussions with the community and the team.
- [GitHub](https://github.com/ToolJet/ToolJet/issues) - For bug reports and feature requests.

View file

@ -1 +1,2 @@
/node_modules
/node_modules
/cypress.env.json

View file

@ -1,6 +1,6 @@
const { defineConfig } = require("cypress");
const { rmdir } = require("fs");
const pg = require('pg');
const pg = require("pg");
module.exports = defineConfig({
execTimeout: 1800000,
@ -12,21 +12,7 @@ module.exports = defineConfig({
viewportHeight: 960,
chromeWebSecurity: false,
trashAssetsBeforeRuns: true,
env: {
pg_host: "",
pg_user: "",
pg_password: "",
sso_password: "",
git_user: "",
google_user: "",
},
db: {
user: "postgres",
host: "localhost",
database: "tooljet_development",
password: "postgres",
port: "5432",
},
e2e: {
setupNodeEvents(on, config) {
on("task", {
@ -44,16 +30,21 @@ module.exports = defineConfig({
});
on("task", {
UpdateId({dbconfig,sql}){
UpdateId({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
}
})
},
});
return require("./cypress/plugins/index.js")(on, config);
},
experimentalRunAllSpecs: true,
experimentalModfyObstructiveThirdPartyCode: true,
experimentalRunAllSpecs: true,
baseUrl: "http://localhost:8082",
specPattern: "cypress/e2e/**/*.cy.js",
numTestsKeptInMemory: 25,
redirectionLimit: 10,
experimentalRunAllSpecs: true,
},
});

View file

@ -0,0 +1,49 @@
{
"sso_password": "",
"git_user": "",
"google_user": "",
"pg_host": "",
"pg_user": "",
"pg_password": "",
"elasticsearch_host": "",
"elasticsearch_user": "",
"elasticsearch_password": "",
"dynamodb_access_key": "",
"dynamodb_secret_key": "",
"smtp_host": "",
"smtp_port": "",
"smtp_user": "",
"smtp_password": "",
"redis_host": "",
"redis_port": "",
"redis_password": "",
"mongodb_connString": "",
"mongodb_host": "",
"mongodb_user": "",
"mongo_password": "",
"bigquery_pvt_key": {},
"firestore_pvt_key": {},
"mysql_host": "",
"mysql_user": "",
"mysql_password": "",
"aws_access": "",
"aws_secret": "",
"app_db": {
"user": "postgres",
"host": "localhost",
"database": "tooljet_development",
"password": "postgres",
"port": "5432"
}
}

View file

@ -0,0 +1,9 @@
export const s3Selector = {
awsDatasource: '[data-cy="data-source-aws s3"]',
accessKeyLabel: '[data-cy="label-access-key"]',
secretKeyLabel: '[data-cy="label-secret-key"]',
regionLabel: '[data-cy="label-region"]',
customEndpointLabel: '[data-cy="label-custom-endpoint"]',
customEndpointInput: '[data-cy="undefined-text-field"]',
dataSourceNameInput: '[data-cy="data-source-name-input-filed"]',
};

View file

@ -15,8 +15,10 @@ export const commonSelectors = {
skipButton: ".driver-close-btn",
skipInstallationModal: "[data-cy=skip-button]",
homePageLogo: "[data-cy=home-page-logo]",
pageLogo: "[data-cy=page-logo]",
workEmailLabel: '[data-cy="work-email-label"]',
workEmailInputField: "[data-cy=work-email-input]",
emailInputError: '[data-cy="email-error-message"]',
passwordLabel: '[data-cy="password-label"]',
forgotPasswordLink: '[data-cy="forgot-password-link"]',
passwordInputField: "[data-cy=password-input-field]",
@ -64,6 +66,7 @@ export const commonSelectors = {
createWorkspaceButton: '[data-cy="create-workspace-button"]',
workspaceLoginUrl: "[data-cy=workspace-login-url]",
workspaceName: '[data-cy="workspace-name"]',
signInHeader: '[data-cy="sign-in-header"]',
signInSubHeader: '[data-cy="sign-in-sub-header"]',
createAnAccountLink: '[data-cy="create-an-account-link"]',
SignUpSectionHeader: '[data-cy="signup-section-header"]',
@ -162,8 +165,8 @@ export const commonWidgetSelector = {
return `[data-cy="${widgetName.toLowerCase()}-invalid-feedback"]`;
},
buttonCloseEditorSideBar: "[data-rb-event-key='close-inpector-light']",
buttonStylesEditorSideBar: "[data-rb-event-key='styles']",
buttonCloseEditorSideBar: "[data-cy='inspector-close-icon']",
buttonStylesEditorSideBar: "[data-cy='sidebar-option-styles']",
WidgetNameInputField: "[data-cy=edit-widget-name]",
tooltipInputField: "[data-cy='tooltip-input-field']",
@ -182,8 +185,10 @@ export const commonWidgetSelector = {
'[data-cy="action-options-action-selection-field"]',
componentTextInput: '[data-cy="action-options-text-input-field"]',
changeLayoutButton: "[data-cy= 'change-layout-button']",
changeLayoutToMobileButton: '[data-cy="button-change-layout-to-desktop"]',
changeLayoutToDesktopButton: '[data-cy="button-change-layout-to-mobile"]',
sidebarinspector: "[data-cy='left-sidebar-inspector-button']",
sidebarinspector: "[data-cy='left-sidebar-inspect-button']",
inspectorNodeComponents: "[data-cy='inspector-node-components']> .node-key",
nodeComponentValue: "[data-cy='inspector-node-value']> .mx-2",
nodeComponentValues: "[data-cy='inspector-node-values']> .node-key",
@ -196,4 +201,4 @@ export const commonWidgetSelector = {
boxShadowColorPicker: "[data-cy='box-shadow-picker']",
textInputWidget: '[data-cy="draggable-widget-textinput1"]',
previewButton: `[data-cy="preview-link-button"]`,
};
};

View file

@ -1,15 +0,0 @@
export const loginSelectors = {
logo: "[data-cy=login-page-logo]",
cardTitle: "[data-cy=login-page-header]",
emailLabel: "[data-cy=email-label]",
emailField: "[data-cy=email-text-field]",
passwordLabel: "[data-cy=password-label]",
forgotPassword: "[data-cy=forgot-password-link]",
passwordField: "[data-cy=password-text-field]",
checkBox: "[data-cy=checkbox-input]",
showPassword: "[data-cy=show-password-label]",
signInButton: "[data-cy=login-button]",
signUpText: "[data-cy=sign-up-message]",
signUpLink: "[data-cy=sign-up-link]",
homePage: "[data-cy=home-page-logo]",
};

View file

@ -1,5 +1,5 @@
export const postgreSqlSelector = {
leftSidebarDatasourceButton: "[data-cy='left-sidebar-sources-button']",
leftSidebarDatasourceButton: "[data-cy='left-sidebar-database-button']",
labelDataSources: "[data-cy='label-datasources']",
addDatasourceLink: "[data-cy='add-datasource-link']",

View file

@ -0,0 +1,18 @@
export const s3Text = {
awsS3: "AWS S3",
accessKey: "Access key",
secretKey: "Secret keyEncrypted",
region: "Region",
customEndpoint: "Custom Endpoint",
alertRegionIsMissing: "Region is missing",
cypressAwsS3: "cypress-aws-s3",
placeholderEnterAccessKey: "Enter access key",
placeholderEnterSecretKey: "Enter secret key",
labelRegion: "Region",
region: "N. california",
alertInvalidUrl: "Invalid URL:",
accessKeyError:
"The AWS Access Key Id you provided does not exist in our records.",
sinatureError:
"The request signature we calculated does not match the signature you provided. Check your key and signing method.",
};

View file

@ -0,0 +1,7 @@
export const bigqueryText = {
bigQuery: "BigQuery",
cypressBigQuery: "cypress-bigquery",
errorInvalidEmailId:
"The incoming JSON object does not contain a client_email field",
placehlderPrivateKey: "Enter JSON private key for service account",
};

View file

@ -12,7 +12,7 @@ export const path = {
};
export const commonText = {
autoSave: "All changes are saved",
autoSave: "Saved changes",
email: "dev@tooljet.io",
password: "password",
loginErrorToast: "Invalid email or password",
@ -51,9 +51,11 @@ export const commonText = {
"Are you sure you want to delete the folder? Apps within the folder will not be deleted.",
closeButton: "modal close",
workEmailLabel: "Email",
emailInputError: "Invalid Email",
passwordLabel: "Password",
forgotPasswordLink: "Forgot?",
loginButton: " Login",
signInHeader: "Sign in",
signInSubHeader: "New to ToolJet?Create an account",
SignUpSectionHeader: "Join ToolJet",
signInRedirectText: "Already have an account?",
@ -139,4 +141,4 @@ export const widgetValue = (widgetName) => {
export const customValidation = (name, message) => {
return ["{{", `components.${name}.value ? true : '${message}'}}`];
};
};

View file

@ -0,0 +1,14 @@
export const dynamoDbText = {
dynamoDb: "DynamoDB",
cypressDynamoDb: "cypress-dynamodb",
region: "Region",
accessKey: "Access key",
placeHolderAccessKey: "Enter access key",
secretKey: "Secret key",
placeholderSecretKey: "Enter secret key",
errorMissingRegion: "Missing region in config",
errorInvalidToken: "The security token included in the request is invalid.",
errorSignatureMissmatch:
"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.",
};

View file

@ -0,0 +1,7 @@
export const elasticsearchText = {
elasticSearch: "Elasticsearch",
cypressElasticsearch: "cypress-elasticsearch",
errorConnectionRefused: "connect ECONNREFUSED 127.0.0.1:9200",
errorGetAddrInfoNotFound: "getaddrinfo ENOTFOUND elasticsearch_host",
};

View file

@ -0,0 +1,10 @@
export const firestoreText = {
firestore: "Firestore",
cypressFirestore: "cypress-firestore",
labelPrivateKey: "Private keyEncrypted",
privateKey: "Private key",
placeholderPrivateKey: "Enter private key",
errorGcpKeyCouldNotBeParsed:
"GCP key could not be parsed as a valid JSON object",
};

View file

@ -1,11 +0,0 @@
export const loginTexts = {
cardTitle: "Login to your account",
emailLabel: "Email address",
passwordLabel: "Password",
forgotPassword: "Forgot Password",
showPassword: "show password",
signIn: "Sign in",
signUpText: "Don't have account yet?",
signUpLink: "Sign up",
toastMessage: "Invalid email or password",
};

View file

@ -0,0 +1,13 @@
export const mongoDbText = {
mongoDb: "MongoDB",
cypressMongoDb: "cypress-mongodb",
errorConnectionRefused: "connect ECONNREFUSED 127.0.0.1:27017",
optionConnectUsingConnectionString: "Connect using connection string{enter}",
labelConnectionString: "Connection string",
errorInvalisScheme:
'Invalid scheme, expected connection string to start with "mongodb://" or "mongodb+srv://"',
connectionStringPlaceholder:
"mongodb+srv://tooljet:<password>@cluster0.i1vq4.mongodb.net/mydb?retryWrites=true&w=majority",
};

View file

@ -0,0 +1,9 @@
export const mySqlText = {
errorConnectionRefused: "connect ECONNREFUSED",
errorUnknownDb: "ER_BAD_DB_ERROR: Unknown database 'test_db1'",
errorAccessDeniedAdmin1:
"ER_ACCESS_DENIED_ERROR: Access denied for user 'admin1'",
errorAccessDeniedAdmin:
"ER_ACCESS_DENIED_ERROR: Access denied for user 'admin'",
cypressMySql: "cypress-mysql",
};

View file

@ -1,5 +1,5 @@
export const postgreSqlText = {
labelDataSources: "Data sources",
labelDataSources: "Datasources",
labelAddDataSource: "+ add data source",
allDataSources: "All Datasources (39)",

View file

@ -0,0 +1,9 @@
export const redisText = {
redis: "Redis",
cypressRedis: "cypress-redis",
errorMaxRetries:
'Reached the max retries per request limit (which is 1). Refer to "maxRetriesPerRequest" option for details.',
errorPort: "Port should be >= 0 and < 65536. Received 108299.",
errorInvalidUserOrPassword: "WRONGPASS invalid username-password pair",
};

View file

@ -1,59 +1,82 @@
import { loginSelectors } from "Selectors/login";
import { commonSelectors } from "Selectors/common";
import { loginTexts } from "Texts/login";
import { fake } from "Fixtures/fake";
import * as login from "Support/utils/login";
import { commonText, path } from "Texts/common";
describe("Login functionality", () => {
let user;
const invalidEmail = fake.email;
const invalidPassword = fake.password;
before(() => {
beforeEach(() => {
cy.fixture("credentials/login.json").then((login) => {
user = login;
});
cy.visit("/");
});
it("Should verify elements on the login page", () => {
login.loginPageElements();
cy.url().should("include", path.loginPath);
cy.get(commonSelectors.pageLogo).should("be.visible");
cy.get(commonSelectors.signInHeader).verifyVisibleElement(
"have.text",
commonText.signInHeader
);
cy.get(commonSelectors.workEmailLabel).verifyVisibleElement(
"have.text",
commonText.workEmailLabel
);
cy.get(commonSelectors.passwordLabel).should(($el) => {
expect($el.contents().first().text().trim()).to.eq(
commonText.passwordLabel
);
});
cy.get(commonSelectors.forgotPasswordLink).verifyVisibleElement(
"have.text",
commonText.forgotPasswordLink
);
cy.get(commonSelectors.loginButton).verifyVisibleElement(
"have.text",
commonText.loginButton
);
cy.get(commonSelectors.workEmailInputField).should("be.visible");
cy.get(commonSelectors.passwordInputField).should("be.visible");
});
it("Should not be able to login with invalid credentials", () => {
cy.get(loginSelectors.signInButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
loginTexts.toastMessage
cy.get(commonSelectors.loginButton).click();
cy.get(commonSelectors.emailInputError).verifyVisibleElement(
"have.text",
commonText.emailInputError
);
cy.clearAndType(loginSelectors.emailField, invalidEmail);
cy.get(loginSelectors.signInButton).click();
cy.clearAndType(commonSelectors.workEmailInputField, invalidEmail);
cy.get(commonSelectors.loginButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
loginTexts.toastMessage
commonText.loginErrorToast
);
cy.get(loginSelectors.emailField).clear();
cy.clearAndType(loginSelectors.passwordField, invalidPassword);
cy.get(loginSelectors.signInButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
loginTexts.toastMessage
cy.get(commonSelectors.workEmailInputField).clear();
cy.clearAndType(commonSelectors.passwordInputField, invalidPassword);
cy.get(commonSelectors.loginButton).click();
cy.get(commonSelectors.emailInputError).verifyVisibleElement(
"have.text",
commonText.emailInputError
);
cy.clearAndType(loginSelectors.emailField, user.email);
cy.get(loginSelectors.passwordField).clear();
cy.get(loginSelectors.signInButton).click();
cy.clearAndType(commonSelectors.workEmailInputField, user.email);
cy.get(commonSelectors.passwordInputField).clear();
cy.get(commonSelectors.loginButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
loginTexts.toastMessage
commonText.loginErrorToast
);
cy.get(loginSelectors.emailField).clear();
cy.clearAndType(loginSelectors.passwordField, user.password);
cy.get(loginSelectors.signInButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
loginTexts.toastMessage
cy.get(commonSelectors.workEmailInputField).clear();
cy.clearAndType(commonSelectors.passwordInputField, user.password);
cy.get(commonSelectors.loginButton).click();
cy.get(commonSelectors.emailInputError).verifyVisibleElement(
"have.text",
commonText.emailInputError
);
});
it("Should be able to login with valid credentials", () => {

View file

@ -0,0 +1,128 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { bigqueryText } from "Texts/bigquery";
import { firestoreText } from "Texts/firestore";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
describe("Data source BigQuery", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
});
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
bigqueryText.bigQuery
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", bigqueryText.bigQuery);
cy.get('[data-cy="data-source-bigquery"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
bigqueryText.bigQuery
);
cy.get('[data-cy="label-private-key"]').verifyVisibleElement(
"have.text",
firestoreText.labelPrivateKey
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect
);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
bigqueryText.errorInvalidEmailId
);
});
it("Should verify the functionality of BigQuery connection form.", () => {
selectDataSource(bigqueryText.bigQuery);
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
bigqueryText.cypressBigQuery
);
fillDataSourceTextField(
firestoreText.privateKey,
bigqueryText.placehlderPrivateKey,
JSON.stringify(Cypress.env("bigquery_pvt_key")),
"contain",
{ parseSpecialCharSequences: false, delay: 0 }
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", bigqueryText.cypressBigQuery)
.find("button")
.should("be.visible");
});
});

View file

@ -0,0 +1,166 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { dynamoDbText } from "Texts/dynamodb";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
dynamoDbText.dynamoDb
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", dynamoDbText.dynamoDb);
cy.get('[data-cy="data-source-dynamodb"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
dynamoDbText.dynamoDb
);
cy.get('[data-cy="label-region"]').verifyVisibleElement(
"have.text",
dynamoDbText.region
);
cy.get('[data-cy="label-access-key"]').verifyVisibleElement(
"have.text",
dynamoDbText.accessKey
);
cy.get('[data-cy="label-secret-key"]').verifyVisibleElement(
"have.text",
dynamoDbText.secretKey
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect
);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
dynamoDbText.errorMissingRegion
);
});
it("Should verify the functionality of DynamoDB connection form.", () => {
selectDataSource(dynamoDbText.dynamoDb);
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
dynamoDbText.cypressDynamoDb
);
cy.get('[data-cy="label-region"]')
.parent()
.next()
.find("input")
.type(`N. california{enter}`);
fillDataSourceTextField(
dynamoDbText.accessKey,
dynamoDbText.placeHolderAccessKey,
"dynamodb_access_key"
);
fillDataSourceTextField(
dynamoDbText.secretKey,
dynamoDbText.placeholderSecretKey,
Cypress.env("dynamodb_secret_key")
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(dynamoDbText.errorInvalidToken);
fillDataSourceTextField(
dynamoDbText.accessKey,
dynamoDbText.placeHolderAccessKey,
Cypress.env("dynamodb_access_key")
);
fillDataSourceTextField(
dynamoDbText.secretKey,
dynamoDbText.placeholderSecretKey,
"dynamodb_secret_key"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(dynamoDbText.errorSignatureMissmatch);
fillDataSourceTextField(
dynamoDbText.secretKey,
dynamoDbText.placeholderSecretKey,
Cypress.env("dynamodb_secret_key")
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified, {
timeout: 10000,
});
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("contains.text", dynamoDbText.cypressDynamoDb)
.should("be.visible");
});
});

View file

@ -0,0 +1,188 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { elasticsearchText } from "Texts/elasticsearch";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
elasticsearchText.elasticSearch
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", elasticsearchText.elasticSearch);
cy.get('[data-cy="data-source-elasticsearch"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
elasticsearchText.elasticSearch
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
postgreSqlText.labelHost
);
cy.get(postgreSqlSelector.labelPort).verifyVisibleElement(
"have.text",
postgreSqlText.labelPort
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
postgreSqlText.labelUserName
);
cy.get(postgreSqlSelector.labelPassword).verifyVisibleElement(
"have.text",
"Password"
);
cy.get(postgreSqlSelector.labelSsl).verifyVisibleElement(
"have.text",
postgreSqlText.labelSSL
);
cy.get(postgreSqlSelector.labelSSLCertificate).verifyVisibleElement(
"have.text",
postgreSqlText.sslCertificate
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect
);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
elasticsearchText.errorConnectionRefused
);
});
it("Should verify the functionality of Elasticsearch connection form.", () => {
selectDataSource(elasticsearchText.elasticSearch);
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
elasticsearchText.cypressElasticsearch
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
"elasticsearch_host"
);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
"443"
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
Cypress.env("elasticsearch_user")
);
cy.get(postgreSqlSelector.passwordTextField).type(
Cypress.env("elasticsearch_password")
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(elasticsearchText.errorGetAddrInfoNotFound);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
Cypress.env("elasticsearch_host")
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"elasticsearch_user"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert("Response Error");
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
Cypress.env("elasticsearch_user")
);
cy.get(postgreSqlSelector.passwordTextField)
.clear()
.type("elasticsearch_password");
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert("Response Error");
cy.get(postgreSqlSelector.passwordTextField)
.clear()
.type(Cypress.env("elasticsearch_password"));
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", elasticsearchText.cypressElasticsearch)
.should("be.visible");
});
});

View file

@ -0,0 +1,127 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { firestoreText } from "Texts/firestore";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
firestoreText.firestore
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", firestoreText.firestore);
cy.get('[data-cy="data-source-firestore"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
firestoreText.firestore
);
cy.get('[data-cy="label-private-key"]').verifyVisibleElement(
"have.text",
firestoreText.labelPrivateKey
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect
);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
firestoreText.errorGcpKeyCouldNotBeParsed
);
});
it("Should verify the functionality of Firestore connection form.", () => {
selectDataSource(firestoreText.firestore);
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
firestoreText.cypressFirestore
);
fillDataSourceTextField(
firestoreText.privateKey,
firestoreText.placeholderPrivateKey,
JSON.stringify(Cypress.env("firestore_pvt_key")),
"contain",
{ parseSpecialCharSequences: false, delay: 0 }
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("contain.text", firestoreText.cypressFirestore)
.find("button")
.should("be.visible");
});
});

View file

@ -0,0 +1,183 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { mongoDbText } from "Texts/mongoDb";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(
mongoDbText.mongoDb
);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", mongoDbText.mongoDb);
cy.get('[data-cy="data-source-mongodb"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
mongoDbText.mongoDb
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
postgreSqlText.labelHost
);
cy.get(postgreSqlSelector.labelPort).verifyVisibleElement(
"have.text",
postgreSqlText.labelPort
);
cy.get(postgreSqlSelector.labelDbName).verifyVisibleElement(
"have.text",
postgreSqlText.labelDbName
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
postgreSqlText.labelUserName
);
cy.get(postgreSqlSelector.labelPassword).verifyVisibleElement(
"have.text",
postgreSqlText.labelPassword
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect,
{ timeout: 65000 }
);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
mongoDbText.errorConnectionRefused
);
cy.get('[data-cy="query-select-dropdown"]').type(
mongoDbText.optionConnectUsingConnectionString
);
cy.get('[data-cy="label-connection-string"]').verifyVisibleElement(
"have.text",
mongoDbText.labelConnectionString
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect,
{ timeout: 60000 }
);
verifyCouldnotConnectWithAlert(mongoDbText.errorInvalisScheme);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
});
it("Should verify the functionality of MongoDB connection form.", () => {
selectDataSource(mongoDbText.mongoDb);
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
mongoDbText.cypressMongoDb
);
cy.get('[data-cy="query-select-dropdown"]').type(
mongoDbText.optionConnectUsingConnectionString
);
fillDataSourceTextField(
mongoDbText.labelConnectionString,
mongoDbText.connectionStringPlaceholder,
Cypress.env("mongodb_connString"),
"contain",
{ parseSpecialCharSequences: false, delay: 0 }
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", mongoDbText.cypressMongoDb)
.find("button")
.should("be.visible");
});
});

View file

@ -0,0 +1,181 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { mySqlText } from "Texts/mysql";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("MySQL");
cy.get("[data-cy*='data-source-']").eq(0).should("contain", "MySQL");
cy.get('[data-cy="data-source-mysql"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
"MySQL"
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
postgreSqlText.labelHost
);
cy.get(postgreSqlSelector.labelPort).verifyVisibleElement(
"have.text",
postgreSqlText.labelPort
);
cy.get(postgreSqlSelector.labelSsl).verifyVisibleElement(
"have.text",
postgreSqlText.labelSSL
);
cy.get(postgreSqlSelector.labelDbName).verifyVisibleElement(
"have.text",
postgreSqlText.labelDbName
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
postgreSqlText.labelUserName
);
cy.get(postgreSqlSelector.labelPassword).verifyVisibleElement(
"have.text",
postgreSqlText.labelPassword
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
verifyCouldnotConnectWithAlert(mySqlText.errorConnectionRefused);
});
it("Should verify the functionality of MySQL connection form.", () => {
selectDataSource("MySQL");
cy.clearAndType(
'[data-cy="data-source-name-input-filed"]',
mySqlText.cypressMySql
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
Cypress.env("mysql_host")
);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
"3306"
);
fillDataSourceTextField(
postgreSqlText.labelDbName,
postgreSqlText.placeholderNameOfDB,
"test_db1"
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"admin"
);
cy.get(postgreSqlSelector.passwordTextField).type(
Cypress.env("mysql_password")
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(mySqlText.errorUnknownDb);
fillDataSourceTextField(
postgreSqlText.labelDbName,
postgreSqlText.placeholderNameOfDB,
"test_db"
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"admin1"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(mySqlText.errorAccessDeniedAdmin1);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"admin"
);
cy.get(postgreSqlSelector.passwordTextField).type("testpassword");
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(mySqlText.errorAccessDeniedAdmin);
cy.get(postgreSqlSelector.passwordTextField).type(
`{selectAll}{backspace}${Cypress.env("mysql_password")}`
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", mySqlText.cypressMySql)
.find("button")
.should("be.visible");
});
});

View file

@ -0,0 +1,188 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { redisText } from "Texts/redis";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(redisText.redis);
cy.get("[data-cy*='data-source-']")
.eq(0)
.should("contain", redisText.redis);
cy.get('[data-cy="data-source-redis"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
redisText.redis
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
postgreSqlText.labelHost
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
"redis_host"
);
cy.get(postgreSqlSelector.labelPort).verifyVisibleElement(
"have.text",
postgreSqlText.labelPort
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
postgreSqlText.labelUserName
);
cy.get(postgreSqlSelector.labelPassword).verifyVisibleElement(
"have.text",
postgreSqlText.labelPassword
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
verifyCouldnotConnectWithAlert(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
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
"redis_host"
);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
Cypress.env("redis_port")
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"dev@tooljet.io"
);
cy.get(postgreSqlSelector.passwordTextField).type(
Cypress.env("redis_password")
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorMaxRetries);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
Cypress.env("redis_host")
);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
"108299"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorPort);
fillDataSourceTextField(
postgreSqlText.labelPort,
postgreSqlText.placeholderEnterPort,
Cypress.env("redis_port")
);
cy.get(postgreSqlSelector.passwordTextField).type(
`{selectAll}{backspace}"redis_password"`
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorInvalidUserOrPassword);
cy.get(postgreSqlSelector.passwordTextField).type(
`{selectAll}{backspace}${Cypress.env("redis_password")}`
);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"dev@tooljet.com"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(redisText.errorInvalidUserOrPassword);
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,
"dev@tooljet.io"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", redisText.cypressRedis)
.find("button")
.should("be.visible");
});
});

View file

@ -0,0 +1,176 @@
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 {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
import { verifyCouldnotConnectWithAlert } from "Support/utils/dataSource";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(s3Text.awsS3);
cy.get("[data-cy*='data-source-']").eq(0).should("contain", s3Text.awsS3);
cy.get(s3Selector.awsDatasource).click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
s3Text.awsS3
);
cy.get(s3Selector.accessKeyLabel).verifyVisibleElement(
"have.text",
s3Text.accessKey
);
cy.get(s3Selector.secretKeyLabel).verifyVisibleElement(
"have.text",
s3Text.secretKey
);
cy.get(s3Selector.regionLabel).verifyVisibleElement(
"have.text",
s3Text.labelRegion
);
cy.get(s3Selector.customEndpointLabel)
.verifyVisibleElement("have.text", s3Text.customEndpoint)
.next()
.find("input")
.click();
cy.get(s3Selector.customEndpointInput).should("be.visible");
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
verifyCouldnotConnectWithAlert(s3Text.alertRegionIsMissing);
});
it("Should verify the functionality of AWS S3 connection form.", () => {
selectDataSource(s3Text.awsS3);
cy.clearAndType(s3Selector.dataSourceNameInput, s3Text.cypressAwsS3);
fillDataSourceTextField(
s3Text.accessKey,
s3Text.placeholderEnterAccessKey,
Cypress.env("aws_access")
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.alertRegionIsMissing);
fillDataSourceTextField(
"Secret key",
s3Text.placeholderEnterSecretKey,
Cypress.env("aws_secret"),
"contain"
);
cy.get(s3Selector.regionLabel)
.next()
.find("input")
.type(`${s3Text.region}{enter}`);
cy.get(s3Selector.customEndpointLabel)
.verifyVisibleElement("have.text", s3Text.customEndpoint)
.next()
.find("input")
.click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.alertInvalidUrl);
cy.get(s3Selector.customEndpointLabel)
.verifyVisibleElement("have.text", s3Text.customEndpoint)
.next()
.find("input")
.click();
fillDataSourceTextField(
s3Text.accessKey,
s3Text.placeholderEnterAccessKey,
"aws_access"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.accessKeyError);
fillDataSourceTextField(
s3Text.accessKey,
s3Text.placeholderEnterAccessKey,
Cypress.env("aws_access")
);
fillDataSourceTextField(
"Secret key",
s3Text.placeholderEnterSecretKey,
"aws_secret",
"contain"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
verifyCouldnotConnectWithAlert(s3Text.sinatureError);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", s3Text.cypressAwsS3)
.find("button")
.should("be.visible");
});
});

View file

@ -0,0 +1,145 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonSelectors } from "Selectors/common";
import {
fillDataSourceTextField,
selectDataSource,
} from "Support/utils/postgreSql";
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)
.click();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.get(postgreSqlSelector.dataSourceSearchInputField).type("SMTP");
cy.get("[data-cy*='data-source-']").eq(0).should("contain", "SMTP");
cy.get('[data-cy="data-source-smtp"]').click();
cy.get(postgreSqlSelector.dataSourceNameInputField).should(
"have.value",
"SMTP"
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
postgreSqlText.labelHost
);
cy.get(postgreSqlSelector.labelPort).verifyVisibleElement(
"have.text",
postgreSqlText.labelPort
);
cy.get('[data-cy="label-user"]').verifyVisibleElement("have.text", "User");
cy.get(postgreSqlSelector.labelPassword).verifyVisibleElement(
"have.text",
"Password"
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
postgreSqlText.whiteListIpText
);
cy.get(postgreSqlSelector.buttonCopyIp).verifyVisibleElement(
"have.text",
postgreSqlText.textCopy
);
cy.get(postgreSqlSelector.linkReadDocumentation).verifyVisibleElement(
"have.text",
postgreSqlText.readDocumentation
);
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect
);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"have.text",
"Invalid credentials"
);
});
it("Should verify the functionality of SMTP connection form.", () => {
selectDataSource("SMTP");
cy.clearAndType(
postgreSqlSelector.dataSourceNameInputField,
"cypress-smtp"
);
fillDataSourceTextField(
postgreSqlText.labelHost,
postgreSqlText.placeholderEnterHost,
Cypress.env("smtp_host")
);
fillDataSourceTextField(
postgreSqlText.labelPort,
"Recommended port 465 (Secured)",
Cypress.env("smtp_port")
);
fillDataSourceTextField(
"User",
postgreSqlText.placeholderEnterUserName,
Cypress.env("smtp_user")
);
cy.get(postgreSqlSelector.passwordTextField).type(
Cypress.env("smtp_password")
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 20000,
}).should("have.text", postgreSqlText.labelConnectionVerified, {
timeout: 10000,
});
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSAdded
);
cy.get(postgreSqlSelector.leftSidebarDatasourceButton).click();
cy.get(postgreSqlSelector.datasourceLabelOnList)
.should("have.text", "cypress-smtp")
.should("be.visible");
});
});

View file

@ -3,9 +3,7 @@ import { buttonText } from "Texts/button";
import { fake } from "Fixtures/fake";
import { commonWidgetText } from "Texts/common";
import {
verifyControlComponentAction,
} from "Support/utils/button";
import { verifyControlComponentAction } from "Support/utils/button";
import {
openAccordion,
@ -25,12 +23,10 @@ import {
verifyTooltip,
editAndVerifyWidgetName,
verifyPropertiesGeneralAccordion,
verifyStylesGeneralAccordion
verifyStylesGeneralAccordion,
} from "Support/utils/commonWidget";
describe("Editor- Test Button widget", () => {
beforeEach(() => {
cy.appUILogin();
cy.createApp();
@ -48,7 +44,7 @@ describe("Editor- Test Button widget", () => {
cy.renameApp(data.appName);
openEditorSidebar(buttonText.defaultWidgetName);
editAndVerifyWidgetName(data.widgetName)
editAndVerifyWidgetName(data.widgetName);
openAccordion(commonWidgetText.accordionProperties);
verifyAndModifyParameter(buttonText.buttonTextLabel, data.widgetName);
@ -81,7 +77,7 @@ describe("Editor- Test Button widget", () => {
verifyLayout(data.widgetName);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(commonWidgetSelector.changeLayoutToDesktopButton).click();
cy.get(
commonWidgetSelector.parameterTogglebutton(
commonWidgetText.parameterShowOnDesktop
@ -124,7 +120,10 @@ describe("Editor- Test Button widget", () => {
commonWidgetSelector.parameterFxButton(buttonText.backgroundColor)
).click();
selectColourFromColourPicker(buttonText.backgroundColor, data.backgroundColor);
selectColourFromColourPicker(
buttonText.backgroundColor,
data.backgroundColor
);
verifyWidgetColorCss(
buttonText.defaultWidgetName,
@ -146,7 +145,7 @@ describe("Editor- Test Button widget", () => {
commonWidgetSelector.parameterFxButton(buttonText.textColor)
).click();
selectColourFromColourPicker(buttonText.textColor, data.textColor);
selectColourFromColourPicker(buttonText.textColor, data.textColor, 1);
verifyWidgetColorCss(buttonText.defaultWidgetName, "color", data.textColor);
@ -164,7 +163,7 @@ describe("Editor- Test Button widget", () => {
commonWidgetSelector.parameterFxButton(buttonText.loaderColor)
).click();
selectColourFromColourPicker(buttonText.loaderColor, data.loaderColor);
selectColourFromColourPicker(buttonText.loaderColor, data.loaderColor, 2);
verifyLoaderColor(buttonText.defaultWidgetName, data.loaderColor);
@ -213,7 +212,13 @@ describe("Editor- Test Button widget", () => {
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
data.colourHex = fake.randomRgbaHex;
verifyStylesGeneralAccordion(buttonText.defaultWidgetName, data.boxShadowParam, data.colourHex, data.boxShadowColor);
verifyStylesGeneralAccordion(
buttonText.defaultWidgetName,
data.boxShadowParam,
data.colourHex,
data.boxShadowColor,
4
);
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
@ -237,26 +242,32 @@ describe("Editor- Test Button widget", () => {
openEditorSidebar(buttonText.defaultWidgetName);
verifyAndModifyParameter(buttonText.buttonTextLabel, data.widgetName);
openAccordion(commonWidgetText.accordionEvents);
openAccordion(commonWidgetText.accordionEvents);
addDefaultEventHandler(data.alertMessage);
verifyPropertiesGeneralAccordion(buttonText.defaultWidgetName, data.tooltipText);
verifyPropertiesGeneralAccordion(
buttonText.defaultWidgetName,
data.tooltipText
);
openEditorSidebar(buttonText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
selectColourFromColourPicker(buttonText.backgroundColor, data.backgroundColor);
cy.get(commonWidgetSelector.buttonCloseEditorSideBar).click();
selectColourFromColourPicker(
buttonText.backgroundColor,
data.backgroundColor
);
cy.forceClickOnCanvas();
openEditorSidebar(buttonText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
selectColourFromColourPicker(buttonText.textColor, data.textColor);
selectColourFromColourPicker(buttonText.textColor, data.textColor, 1);
cy.get(commonWidgetSelector.buttonCloseEditorSideBar).click();
cy.forceClickOnCanvas();
openEditorSidebar(buttonText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
selectColourFromColourPicker(buttonText.loaderColor, data.loaderColor);
selectColourFromColourPicker(buttonText.loaderColor, data.loaderColor, 2);
cy.get(commonWidgetSelector.buttonCloseEditorSideBar).click();
cy.forceClickOnCanvas();
openEditorSidebar(buttonText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
@ -269,9 +280,18 @@ describe("Editor- Test Button widget", () => {
.clear()
.type(buttonText.borderRadiusInput);
verifyStylesGeneralAccordion(buttonText.defaultWidgetName, data.boxShadowParam, data.colourHex, data.boxShadowColor);
verifyStylesGeneralAccordion(
buttonText.defaultWidgetName,
data.boxShadowParam,
data.colourHex,
data.boxShadowColor,
4
);
verifyControlComponentAction(buttonText.defaultWidgetName, data.customMessage);
verifyControlComponentAction(
buttonText.defaultWidgetName,
data.customMessage
);
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
@ -280,9 +300,11 @@ describe("Editor- Test Button widget", () => {
commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)
).verifyVisibleElement("have.text", data.widgetName);
cy.get(commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)).click();
cy.get(
commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)
).click();
cy.verifyToastMessage(commonSelectors.toastMessage, data.alertMessage);
cy.get(commonWidgetSelector.draggableWidget('textinput1')).should(
cy.get(commonWidgetSelector.draggableWidget("textinput1")).should(
"have.value",
data.customMessage
);
@ -292,17 +314,23 @@ describe("Editor- Test Button widget", () => {
data.tooltipText
);
verifyWidgetColorCss(buttonText.defaultWidgetName, "background-color", data.backgroundColor);
verifyWidgetColorCss(
buttonText.defaultWidgetName,
"background-color",
data.backgroundColor
);
verifyWidgetColorCss(buttonText.defaultWidgetName, "color", data.textColor);
verifyLoaderColor(buttonText.defaultWidgetName, data.loaderColor);
cy.get(commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)).should(
"have.css",
"border-radius",
"20px"
);
cy.get(
commonWidgetSelector.draggableWidget(buttonText.defaultWidgetName)
).should("have.css", "border-radius", "20px");
verifyBoxShadowCss(buttonText.defaultWidgetName, data.boxShadowColor, data.boxShadowParam);
verifyBoxShadowCss(
buttonText.defaultWidgetName,
data.boxShadowColor,
data.boxShadowParam
);
cy.get(commonSelectors.viewerPageLogo).click();
cy.deleteApp(data.appName);

View file

@ -0,0 +1,604 @@
import { commonWidgetSelector, commonSelectors } from "Selectors/common";
import { fake } from "Fixtures/fake";
import { tableText } from "Texts/table";
import { tableSelector } from "Selectors/table";
import {
verifyComponent,
deleteComponentAndVerify,
verifyComponentWithOutLabel
} from "Support/utils/basicComponents";
import {
openAccordion,
verifyAndModifyParameter,
openEditorSidebar,
verifyAndModifyToggleFx,
addDefaultEventHandler,
addAndVerifyTooltip,
editAndVerifyWidgetName,
verifyComponentValueFromInspector,
fillBoxShadowParams,
selectColourFromColourPicker,
addTextWidgetToVerifyValue,
verifyBoxShadowCss,
verifyTooltip,
verifyWidgetText,
closeAccordions,
} from "Support/utils/commonWidget";
import {
commonText,
commonWidgetText,
codeMirrorInputLabel,
} from "Texts/common";
describe("Basic components", () => {
const data = {};
beforeEach(() => {
data.appName = `${fake.companyName}-App`;
cy.appUILogin();
cy.createApp();
cy.modifyCanvasSize(900, 900);
cy.renameApp(data.appName);
});
it("Should verify Toggle switch", () => {
cy.dragAndDropWidget("Toggle Switch", 50, 50);
verifyComponent("toggleswitch1");
cy.resizeWidget("toggleswitch1", 850, 600);
openEditorSidebar("toggleswitch1");
editAndVerifyWidgetName("toggleswitch2");
verifyAndModifyParameter(commonWidgetText.parameterLabel, "label");
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("toggleswitch2");
cy.go("back");
deleteComponentAndVerify("toggleswitch2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Checkbox", () => {
cy.dragAndDropWidget("Checkbox", 50, 50);
cy.resizeWidget("checkbox1", 100, 200);
cy.forceClickOnCanvas();
verifyComponent("checkbox1");
cy.resizeWidget("checkbox1", 850, 600);
openEditorSidebar("checkbox1");
editAndVerifyWidgetName("checkbox2");
verifyAndModifyParameter(commonWidgetText.parameterLabel, "label");
cy.forceClickOnCanvas();
cy.get('[data-cy="draggable-widget-checkbox2"] .form-check-label').should(
"have.text",
"label"
);
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("checkbox2");
cy.go("back");
deleteComponentAndVerify("checkbox2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Radio Button", () => {
cy.dragAndDropWidget("Radio Button", 50, 50);
// cy.resizeWidget("radiobutton1", 100, 200);
cy.forceClickOnCanvas();
verifyComponent("radiobutton1");
cy.resizeWidget("radiobutton1", 850, 600);
openEditorSidebar("radiobutton1");
editAndVerifyWidgetName("radiobutton2");
verifyAndModifyParameter(commonWidgetText.parameterLabel, "label");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get('[data-cy="draggable-widget-radiobutton2"] > .col-auto').should(
"have.text",
"label"
);
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("radiobutton2");
cy.go("back");
deleteComponentAndVerify("radiobutton2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Dropdown", () => {
cy.dragAndDropWidget("Dropdown", 50, 50);
// cy.resizeWidget("radiobutton1", 100, 200);
cy.forceClickOnCanvas();
verifyComponent("dropdown1");
cy.resizeWidget("dropdown1", 850, 600);
openEditorSidebar("dropdown1");
editAndVerifyWidgetName("dropdown2");
verifyAndModifyParameter(commonWidgetText.parameterLabel, "label");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get('[data-cy="draggable-widget-dropdown2"] > .col-auto').should(
"have.text",
"label"
);
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("dropdown2");
cy.go("back");
deleteComponentAndVerify("dropdown2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
//pending
it("Should verify Rating", () => {
cy.dragAndDropWidget("Rating", 300, 300);
cy.get('[data-cy="draggable-widget-starrating1"]').click({ force: true });
// cy.resizeWidget("starrating1", 300, 500);
cy.forceClickOnCanvas();
verifyComponent("starrating1");
cy.resizeWidget("starrating1", 850, 600);
openEditorSidebar("starrating1");
editAndVerifyWidgetName("starrating2");
verifyAndModifyParameter(commonWidgetText.parameterLabel, "label");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get('[data-cy="draggable-widget-starrating2"] > .col-auto').should(
"have.text",
"label"
);
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("starrating2");
cy.go("back");
deleteComponentAndVerify("starrating2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Button Group", () => {
cy.dragAndDropWidget("Button Group", 300, 300);
cy.forceClickOnCanvas();
verifyComponent("buttongroup1");
cy.resizeWidget("buttongroup1", 850, 600);
openEditorSidebar("buttongroup1");
editAndVerifyWidgetName("buttongroup2");
verifyAndModifyParameter(commonWidgetText.parameterLabel, "label");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get(
'[data-cy="draggable-widget-buttongroup2"] > .widget-buttongroup-label'
).should("have.text", "label");
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("buttongroup2");
cy.go("back");
deleteComponentAndVerify("buttongroup2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Calendar", () => {
cy.dragAndDropWidget("Calendar", 50, 50);
cy.get('[data-tip="Hide query editor"]').click();
cy.get('[data-cy="draggable-widget-calendar1"]').click({ force: true });
cy.forceClickOnCanvas();
verifyComponent("calendar1");
cy.resizeWidget("calendar1", 850, 600);
openEditorSidebar("calendar1");
editAndVerifyWidgetName("calendar2");
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("calendar2");
cy.go("back");
deleteComponentAndVerify("calendar2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Chart", () => {
cy.dragAndDropWidget("Chart", 50, 50);
cy.get('[data-cy="draggable-widget-chart1"]').click({ force: true });
cy.forceClickOnCanvas();
verifyComponent("chart1");
cy.resizeWidget("chart1", 850, 600);
openEditorSidebar("chart1");
editAndVerifyWidgetName("chart2", ["Chart data", "Properties"]);
verifyAndModifyParameter("Title", "label");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get('[data-cy="draggable-widget-chart2"]').should(
"contain.text",
"label"
);
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("chart2");
cy.go("back");
deleteComponentAndVerify("chart2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Circular Progress Bar", () => {
cy.dragAndDropWidget("Circular Progressbar", 300, 300);
cy.forceClickOnCanvas();
verifyComponent("circularprogressbar1");
cy.resizeWidget("circularprogressbar1", 850, 600);
openEditorSidebar("circularprogressbar1");
editAndVerifyWidgetName("circularprogressbar2");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("circularprogressbar2");
cy.go("back");
deleteComponentAndVerify("circularprogressbar2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Code Editor", () => {
cy.dragAndDropWidget("Code Editor", 300, 300);
cy.get('[data-cy="draggable-widget-codeeditor1"]').click({ force: true });
cy.forceClickOnCanvas();
verifyComponent("codeeditor1");
cy.resizeWidget("codeeditor1", 850, 600);
openEditorSidebar("codeeditor1");
editAndVerifyWidgetName("codeeditor2");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("codeeditor2");
cy.go("back");
deleteComponentAndVerify("codeeditor2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Color Picker", () => {
cy.dragAndDropWidget("Color Picker", 300, 300);
cy.get('[data-cy="draggable-widget-colorpicker1"]').click({ force: true });
cy.forceClickOnCanvas();
verifyComponent("colorpicker1");
cy.resizeWidget("colorpicker1", 850, 600);
openEditorSidebar("colorpicker1");
editAndVerifyWidgetName("colorpicker2");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("colorpicker2");
cy.go("back");
deleteComponentAndVerify("colorpicker2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
//needed fix
it.skip("Should verify Custom Component", () => {
cy.dragAndDropWidget("Custom Component", 50, 50);
cy.get('[data-cy="draggable-widget-customcomponent1"]').click({ force: true });
cy.forceClickOnCanvas();
verifyComponent("customcomponent1");
openEditorSidebar("customcomponent1");
// editAndVerifyWidgetName("customcomponent2", ["Code"]);
closeAccordions(["Code"]);
cy.get(commonWidgetSelector.WidgetNameInputField).type("{selectAll}{backspace}customcomponent2", {delay:30});
cy.forceClickOnCanvas()
cy.get(commonWidgetSelector.draggableWidget(name)).trigger("mouseover");
cy.get(commonWidgetSelector.widgetConfigHandle(name))
.click()
.should("have.text", name);
cy.resizeWidget("customcomponent1", 850, 600);
openEditorSidebar("customcomponent1");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("customcomponent2", ["Code"]);
cy.go("back");
deleteComponentAndVerify("customcomponent2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Container", () => {
cy.dragAndDropWidget("Container", 50, 50);
cy.forceClickOnCanvas();
verifyComponent("container1");
cy.resizeWidget("container1", 850, 600);
openEditorSidebar("container1");
editAndVerifyWidgetName("container2", ["Layout"]);
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("container2", ["Layout"]);
cy.go("back");
deleteComponentAndVerify("container2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Date-Range Picker", () => {
cy.dragAndDropWidget("Range Picker", 300, 300);
cy.forceClickOnCanvas();
verifyComponent("daterangepicker1");
cy.resizeWidget("daterangepicker1", 850, 600);
openEditorSidebar("daterangepicker1");
editAndVerifyWidgetName("daterangepicker2");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("daterangepicker2");
cy.go("back");
deleteComponentAndVerify("daterangepicker2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
//visible issue
it.skip("Should verify Divider", () => {
verifyComponentWithOutLabel("Divider", "divider1", "divider2", data.appName)
});
it("Should verify File Picker", () => {
verifyComponentWithOutLabel("File Picker", "filepicker1", "filepicker2", data.appName)
});
it("Should verify Form", () => {
cy.dragAndDropWidget("Form", 50, 50);
verifyComponent("form1");
cy.resizeWidget("form1", 850, 600);
openEditorSidebar("form1");
editAndVerifyWidgetName("form2");
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("form2");
cy.go("back");
deleteComponentAndVerify("form2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify HTML", () => {
cy.dragAndDropWidget("HTML Viewe", 50, 50, "HTML Viewer"); // search logic WIP
verifyComponent("html1");
cy.resizeWidget("html1", 850, 600);
openEditorSidebar("html1");
editAndVerifyWidgetName("html2");
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("html2");
cy.go("back");
deleteComponentAndVerify("html2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Icon", () => {
verifyComponentWithOutLabel("Icon", "icon1", "icon2", data.appName)
});
it("Should verify Iframe", () => {
verifyComponentWithOutLabel("Iframe", "iframe1", "iframe2", data.appName)
});
it("Should verify Kamban", () => {
verifyComponentWithOutLabel("Kanban Board", "kanbanboard1", "kanbanboard2", data.appName) });
it("Should verify Link", () => {
verifyComponentWithOutLabel("Link", "link1", "link2", data.appName)
});
it("Should verify Map", () => {
cy.dragAndDropWidget("Map", 50, 50);
cy.get("body").then($body => {
if ($body.find(".dismissButton").length > 0) {
cy.get('.dismissButton').click();
}
})
verifyComponent("map1");
cy.resizeWidget("map1", 850, 600);
openEditorSidebar("map1");
editAndVerifyWidgetName("map2");
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("map2");
cy.go("back");
deleteComponentAndVerify("map2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Modal", () => {
verifyComponentWithOutLabel("Modal", "modal1", "modal2", data.appName)
});
it("Should verify PDF", () => {
cy.dragAndDropWidget("PDF", 50, 50);
cy.get('[data-tip="Hide query editor"]').click();
verifyComponent("pdf1");
cy.resizeWidget("pdf1", 850, 600);
openEditorSidebar("pdf1");
editAndVerifyWidgetName("pdf2");
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("pdf2");
cy.go("back");
deleteComponentAndVerify("pdf2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Pagination", () => {
verifyComponentWithOutLabel("Pagination", "pagination1", "pagination2", data.appName)
});
it("Should verify QR Scanner", () => {
verifyComponentWithOutLabel("QR Scanner", "qrscanner1", "qrscanner2", data.appName)
});
it("Should verify Range Slider", () => {
verifyComponentWithOutLabel("Range Slider", "rangeslider1", "rangeslider2", data.appName)
});
it("Should verify Rich Text Editor", () => {
verifyComponentWithOutLabel("Text Editor", "richtexteditor1", "richtexteditor2", data.appName)
});
it("Should verify Spinner", () => {
verifyComponentWithOutLabel("Spinner", "spinner1", "spinner2", data.appName);
});
it("Should verify Statistics", () => {
verifyComponentWithOutLabel("Statistics", "statistics1", "statistics2", data.appName)
});
it("Should verify Steps", () => {
verifyComponentWithOutLabel("Steps", "steps1", "steps2", data.appName)
});
it("Should verify SVG Image", () => {
verifyComponentWithOutLabel("SVG Image", "svgimage1", "svgimage2", data.appName)
});
it("Should verify Tabs", () => {
cy.dragAndDropWidget("Tabs", 50, 50);
verifyComponent("tabs1");
deleteComponentAndVerify("image1");
cy.resizeWidget("tabs1", 850, 600);
openEditorSidebar("tabs1");
editAndVerifyWidgetName("tabs2");
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent("tabs2");
cy.go("back");
deleteComponentAndVerify("tabs2");
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(data.appName);
});
it("Should verify Tags", () => {
verifyComponentWithOutLabel("Tags", "tags1", "tags2", data.appName)
});
it("Should verify Textarea", () => {
verifyComponentWithOutLabel("Textarea", "textarea1", "textarea2", data.appName)
});
it("Should verify Timeline", () => {
verifyComponentWithOutLabel("Timeline", "timeline1", "timeline2", data.appName)
});
it("Should verify Timer", () => {
verifyComponentWithOutLabel("Timer", "timer1", "timer2", data.appName)
});
it("Should verify Tree Select", () => {
verifyComponentWithOutLabel("Tree Select", "treeselect1", "treeselect2", data.appName)
});
it("Should verify Vertical Divider", () => {
verifyComponentWithOutLabel("Vertical Divider", "verticaldivider1", "verticaldivider2", data.appName)
});
});

View file

@ -66,7 +66,7 @@ describe("Date Picker widget", () => {
verifyAndModifyParameter(datePickerText.labelformat, "DD/MM/YY");
cy.get(commonWidgetSelector.buttonCloseEditorSideBar).click();
verifyDate(data.widgetName, data.date, "DD/MM/YY");
verifyComponentValueFromInspector(data.widgetName, data.date, "opened");
verifyComponentValueFromInspector(data.widgetName, data.date);
cy.get(commonSelectors.canvas).click({ force: true });
openEditorSidebar(data.widgetName);
@ -156,14 +156,14 @@ describe("Date Picker widget", () => {
"not.exist"
);
verifyAndModifyToggleFx(
commonWidgetText.parameterShowOnMobile,
commonWidgetText.codeMirrorLabelFalse
);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(commonWidgetSelector.draggableWidget(data.widgetName)).should(
"exist"
);
// verifyAndModifyToggleFx(
// commonWidgetText.parameterShowOnMobile,
// commonWidgetText.codeMirrorLabelFalse
// );
// cy.get(commonWidgetSelector.changeLayoutButton).click();
// cy.get(commonWidgetSelector.draggableWidget(data.widgetName)).should(
// "exist"
// );
});
it("should verify the styles of the date picker widget", () => {
@ -278,7 +278,7 @@ describe("Date Picker widget", () => {
commonWidgetText.borderRadiusInput
);
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
cy.get(
commonWidgetSelector.stylePicker(commonWidgetText.parameterBoxShadow)

View file

@ -175,14 +175,14 @@ describe("List view widget", () => {
"not.exist"
);
verifyAndModifyToggleFx(
commonWidgetText.parameterShowOnMobile,
commonWidgetText.codeMirrorLabelFalse
);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(commonWidgetSelector.draggableWidget(data.widgetName)).should(
"exist"
);
// verifyAndModifyToggleFx(
// commonWidgetText.parameterShowOnMobile,
// commonWidgetText.codeMirrorLabelFalse
// );
// cy.get(commonWidgetSelector.changeLayoutButton).click();
// cy.get(commonWidgetSelector.draggableWidget(data.widgetName)).should(
// "exist"
// );
});
it("should verify the styles of the list view widget", () => {
@ -230,7 +230,7 @@ describe("List view widget", () => {
openEditorSidebar(listviewText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
verifyAndModifyToggleFx(
commonWidgetText.parameterBoxShadow,
@ -246,7 +246,11 @@ describe("List view widget", () => {
data.boxShadowParam
);
selectColourFromColourPicker(commonWidgetText.boxShadowColor, data.colour);
selectColourFromColourPicker(
commonWidgetText.boxShadowColor,
data.colour,
2
);
verifyBoxShadowCss(
listviewText.defaultWidgetName,
data.colour,
@ -368,7 +372,7 @@ describe("List view widget", () => {
openEditorSidebar(listviewText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
verifyAndModifyToggleFx(
commonWidgetText.parameterBoxShadow,
@ -381,7 +385,11 @@ describe("List view widget", () => {
commonWidgetSelector.boxShadowDefaultParam,
data.boxShadowParam
);
selectColourFromColourPicker(commonWidgetText.boxShadowColor, data.colour);
selectColourFromColourPicker(
commonWidgetText.boxShadowColor,
data.colour,
2
);
cy.openInCurrentTab(commonWidgetSelector.previewButton);

View file

@ -79,11 +79,7 @@ describe("Multiselect widget", () => {
commonWidgetText.labelDefaultValue,
codeMirrorInputLabel("[1,2]")
);
verifyMultipleComponentValuesFromInspector(
data.widgetName,
[1, 2],
"opened"
);
verifyMultipleComponentValuesFromInspector(data.widgetName, [1, 2]);
verifyMultiselectHeader(data.widgetName, "one, two");
verifyMultiselectStatus(data.widgetName);
@ -96,11 +92,7 @@ describe("Multiselect widget", () => {
multiselectText.labelAllItemsSelected
);
verifyMultipleComponentValuesFromInspector(
data.widgetName,
[1, 2, 3],
"opened"
);
verifyMultipleComponentValuesFromInspector(data.widgetName, [1, 2, 3]);
openEditorSidebar(data.widgetName);
verifyAndModifyParameter(
@ -111,8 +103,7 @@ describe("Multiselect widget", () => {
verifyMultipleComponentValuesFromInspector(
data.widgetName,
data.randomLabels,
"opened"
data.randomLabels
);
openEditorSidebar(data.widgetName);
@ -169,14 +160,14 @@ describe("Multiselect widget", () => {
"not.exist"
);
verifyAndModifyToggleFx(
commonWidgetText.parameterShowOnMobile,
commonWidgetText.codeMirrorLabelFalse
);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(commonWidgetSelector.draggableWidget(data.widgetName)).should(
"exist"
);
// verifyAndModifyToggleFx(
// commonWidgetText.parameterShowOnMobile,
// commonWidgetText.codeMirrorLabelFalse
// );
// cy.get(commonWidgetSelector.changeLayoutButton).click();
// cy.get(commonWidgetSelector.draggableWidget(data.widgetName)).should(
// "exist"
// );
});
it("should verify the styles of the widget", () => {
@ -223,7 +214,7 @@ describe("Multiselect widget", () => {
openEditorSidebar(multiselectText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
verifyAndModifyStylePickerFx(
commonWidgetText.parameterBoxShadow,
@ -288,7 +279,7 @@ describe("Multiselect widget", () => {
openEditorSidebar(data.widgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
cy.get(
commonWidgetSelector.stylePicker(commonWidgetText.parameterBoxShadow)

View file

@ -117,14 +117,14 @@ describe("Number Input", () => {
verifyPropertiesGeneralAccordion(data.widgetName, data.tooltipText);
verifyLayout(data.widgetName);
// verifyLayout(data.widgetName);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(
commonWidgetSelector.parameterTogglebutton(
commonWidgetText.parameterShowOnDesktop
)
).click();
// cy.get(commonWidgetSelector.changeLayoutButton).click();
// cy.get(
// commonWidgetSelector.parameterTogglebutton(
// commonWidgetText.parameterShowOnDesktop
// )
// ).click();
cy.get(commonWidgetSelector.widgetDocumentationLink).should(
"have.text",
@ -189,7 +189,8 @@ describe("Number Input", () => {
numberInputText.defaultWidgetName,
data.boxShadowParam,
data.colourHex,
data.boxShadowColor
data.boxShadowColor,
3
);
cy.get(commonSelectors.editorPageLogo).click();
@ -245,7 +246,7 @@ describe("Number Input", () => {
openEditorSidebar(numberInputText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
cy.get(commonWidgetSelector.boxShadowColorPicker).click();
fillBoxShadowParams(
@ -254,7 +255,8 @@ describe("Number Input", () => {
);
selectColourFromColourPicker(
commonWidgetText.boxShadowColor,
data.boxShadowColor
data.boxShadowColor,
3
);
addTextWidgetToVerifyValue("components.numberinput1.value");

View file

@ -154,14 +154,14 @@ describe("Password Input", () => {
cy.get(
commonWidgetSelector.accordion(commonWidgetText.accordionValidation)
).click();
verifyLayout(data.widgetName);
// verifyLayout(data.widgetName);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(
commonWidgetSelector.parameterTogglebutton(
commonWidgetText.parameterShowOnDesktop
)
).click();
// cy.get(commonWidgetSelector.changeLayoutButton).click();
// cy.get(
// commonWidgetSelector.parameterTogglebutton(
// commonWidgetText.parameterShowOnDesktop
// )
// ).click();
cy.get(commonWidgetSelector.widgetDocumentationLink).should(
"have.text",
@ -226,7 +226,8 @@ describe("Password Input", () => {
passwordInputText.defaultWidgetName,
data.boxShadowParam,
data.colourHex,
data.boxShadowColor
data.boxShadowColor,
1
);
cy.get(commonSelectors.editorPageLogo).click();
@ -299,7 +300,7 @@ describe("Password Input", () => {
openEditorSidebar(passwordInputText.defaultWidgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
cy.get(commonWidgetSelector.boxShadowColorPicker).click();
fillBoxShadowParams(
@ -308,7 +309,8 @@ describe("Password Input", () => {
);
selectColourFromColourPicker(
commonWidgetText.boxShadowColor,
data.boxShadowColor
data.boxShadowColor,
1
);
addTextWidgetToVerifyValue("components.passwordinput1.value");
cy.waitForAutoSave();
@ -335,6 +337,7 @@ describe("Password Input", () => {
cy.get(
commonWidgetSelector.draggableWidget(commonWidgetText.text1)
).verifyVisibleElement("have.text", "t");
cy.forceClickOnCanvas();
cy.get(
commonWidgetSelector.validationFeedbackMessage(
passwordInputText.defaultWidgetName

View file

@ -173,7 +173,7 @@ describe("Text Input", () => {
).click();
verifyLayout(data.widgetName);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(commonWidgetSelector.changeLayoutToDesktopButton).click();
cy.get(
commonWidgetSelector.parameterTogglebutton(
commonWidgetText.parameterShowOnDesktop
@ -245,7 +245,8 @@ describe("Text Input", () => {
textInputText.defaultWidgetName,
data.boxShadowParam,
data.colourHex,
data.boxShadowColor
data.boxShadowColor,
4
);
cy.get(commonSelectors.editorPageLogo).click();
@ -321,7 +322,8 @@ describe("Text Input", () => {
textInputText.defaultWidgetName,
data.boxShadowParam,
data.colourHex,
data.boxShadowColor
data.boxShadowColor,
4
);
cy.waitForAutoSave();

View file

@ -1,12 +0,0 @@
{
"compilerOptions": {
"paths": {
"Texts/*": [
"./constants/texts/*"
],
"Selectors/*": [
"./constants/selectors/*"
]
}
}
}

View file

@ -1,18 +1,16 @@
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { dashboardSelector } from "Selectors/dashboard";
import { loginSelectors } from "Selectors/login";
import { ssoSelector } from "Selectors/manageSSO";
import { commonText, createBackspaceText } from "Texts/common";
import { passwordInputText } from "Texts/passwordInput";
Cypress.Commands.add("login", (email, password) => {
cy.visit("/");
cy.clearAndType(loginSelectors.emailField, email);
cy.clearAndType(loginSelectors.passwordField, password);
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=").as("homePage");
cy.get(loginSelectors.signInButton).click();
cy.get(loginSelectors.homePage).should("be.visible");
cy.wait("@homePage");
cy.clearAndType(commonSelectors.workEmailInputField, "dev@tooljet.io");
cy.clearAndType(commonSelectors.passwordInputField, "password");
cy.get(commonSelectors.signInButton).click();
cy.get(commonSelectors.homePageLogo).should("be.visible");
cy.wait(2000)
});
Cypress.Commands.add("clearAndType", (selector, text) => {
@ -24,7 +22,7 @@ Cypress.Commands.add("forceClickOnCanvas", () => {
});
Cypress.Commands.add("verifyToastMessage", (selector, message) => {
cy.get(selector).should("be.visible").and("have.text", message);
cy.get(selector).eq(0).should("be.visible").and("have.text", message);
cy.get("body").then(($body) => {
if ($body.find(commonSelectors.toastCloseButton).length > 0) {
cy.closeToastMessage();
@ -108,11 +106,11 @@ Cypress.Commands.add("createApp", (appName) => {
Cypress.Commands.add(
"dragAndDropWidget",
(widgetName, positionX = 190, positionY = 80) => {
(widgetName, positionX = 190, positionY = 80, widgetName2=widgetName) => {
const dataTransfer = new DataTransfer();
cy.clearAndType(commonSelectors.searchField, widgetName);
cy.get(commonWidgetSelector.widgetBox(widgetName)).trigger(
cy.get(commonWidgetSelector.widgetBox(widgetName2)).trigger(
"dragstart",
{ dataTransfer },
{ force: true }
@ -129,9 +127,9 @@ Cypress.Commands.add("appUILogin", () => {
cy.visit("/");
cy.clearAndType(commonSelectors.workEmailInputField, "dev@tooljet.io");
cy.clearAndType(commonSelectors.passwordInputField, "password");
cy.get(loginSelectors.signInButton).click();
cy.get(commonSelectors.signInButton).click();
cy.get(commonSelectors.homePageLogo).should("be.visible");
cy.wait(2000)
cy.wait(2000);
cy.get("body").then(($el) => {
if ($el.text().includes("Skip")) {
cy.get(commonSelectors.skipInstallationModal).click();

View file

@ -0,0 +1,45 @@
import { commonWidgetSelector, commonSelectors } from "Selectors/common";
import {
openAccordion,
verifyAndModifyParameter,
openEditorSidebar,
editAndVerifyWidgetName,
} from "Support/utils/commonWidget";
export const verifyComponent = (widgetName) => {
cy.get(commonWidgetSelector.draggableWidget(widgetName)).should("be.visible");
};
export const deleteComponentAndVerify = (widgetName) => {
cy.get(commonWidgetSelector.draggableWidget(widgetName)).click();
cy.get(`[data-cy="${widgetName}-delete-button"]`).last().click();
cy.notVisible(commonWidgetSelector.draggableWidget(widgetName));
};
export const verifyComponentWithOutLabel=(component, defaultName, fakeName, appName, properties=[] )=>{
cy.dragAndDropWidget(component, 50, 50);
cy.get(`[data-cy="draggable-widget-${defaultName}"]`).click({ force: true });
verifyComponent(defaultName);
cy.resizeWidget(defaultName, 850, 600);
openEditorSidebar(defaultName);
editAndVerifyWidgetName(fakeName, properties);
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.openInCurrentTab(commonWidgetSelector.previewButton);
verifyComponent(fakeName);
cy.go("back");
deleteComponentAndVerify(fakeName);
cy.get(commonSelectors.editorPageLogo).click();
cy.deleteApp(appName);
}

View file

@ -82,8 +82,11 @@ export const addAndVerifyTooltip = (widgetSelector, message) => {
verifyTooltip(widgetSelector, message);
};
export const editAndVerifyWidgetName = (name) => {
closeAccordions(["General", "Properties", "Layout"]);
export const editAndVerifyWidgetName = (
name,
accordion = ["General", "Properties", "Layout"]
) => {
closeAccordions(accordion);
cy.clearAndType(commonWidgetSelector.WidgetNameInputField, name);
cy.get(commonWidgetSelector.buttonCloseEditorSideBar).click();
@ -125,25 +128,27 @@ export const verifyMultipleComponentValuesFromInspector = (
cy.forceClickOnCanvas();
};
export const selectColourFromColourPicker = (paramName, colour) => {
export const selectColourFromColourPicker = (paramName, colour, index = 0) => {
cy.get(commonWidgetSelector.stylePicker(paramName)).click();
cy.get(commonWidgetSelector.colourPickerParent).within(() => {
colour.forEach((value, i) =>
cy
.get(commonWidgetSelector.colourPickerInput(i + 1))
.click()
.clear()
.type(value)
.then(($input) => {
if (!$input.val(value)) {
cy.get(commonWidgetSelector.colourPickerInput(i + 1))
.click()
.clear()
.type(value);
}
})
);
});
cy.get(commonWidgetSelector.colourPickerParent)
.eq(index)
.within(() => {
colour.forEach((value, i) =>
cy
.get(commonWidgetSelector.colourPickerInput(i + 1))
.click()
.clear()
.type(value)
.then(($input) => {
if (!$input.val(value)) {
cy.get(commonWidgetSelector.colourPickerInput(i + 1))
.click()
.clear()
.type(value);
}
})
);
});
cy.waitForAutoSave();
};
@ -194,7 +199,8 @@ export const verifyComponentFromInspector = (
export const verifyAndModifyStylePickerFx = (
paramName,
defaultValue,
value
value,
index = 0
) => {
cy.get(commonWidgetSelector.parameterLabel(paramName)).should(
"have.text",
@ -227,9 +233,11 @@ export const verifyAndModifyStylePickerFx = (
commonWidgetSelector.stylePickerFxInput(paramName)
).clearAndTypeOnCodeMirror(value);
cy.get(commonWidgetSelector.stylePickerFxInput(paramName)).within(() => {
cy.get(".CodeMirror-line").should("be.visible").and("have.text", value);
});
cy.get(commonWidgetSelector.stylePickerFxInput(paramName))
.eq(index)
.within(() => {
cy.get(".CodeMirror-line").should("be.visible").and("have.text", value);
});
};
export const verifyWidgetColorCss = (widgetName, cssProperty, color) => {
@ -266,7 +274,7 @@ export const verifyLayout = (widgetName) => {
commonWidgetText.parameterShowOnMobile,
commonWidgetText.codeMirrorLabelFalse
);
cy.get(commonWidgetSelector.changeLayoutButton).click();
cy.get(commonWidgetSelector.changeLayoutToMobileButton).click();
cy.get(commonWidgetSelector.draggableWidget(widgetName)).should("exist");
};
@ -285,11 +293,12 @@ export const verifyStylesGeneralAccordion = (
widgetName,
boxShadowParameter,
hexColor,
boxShadowColor
boxShadowColor,
index = 0
) => {
openEditorSidebar(widgetName);
cy.get(commonWidgetSelector.buttonStylesEditorSideBar).click();
openAccordion(commonWidgetText.accordionGenaral, [], "1");
openAccordion(commonWidgetText.accordionGenaral, []);
verifyAndModifyStylePickerFx(
commonWidgetText.parameterBoxShadow,
commonWidgetText.boxShadowDefaultValue,
@ -307,7 +316,11 @@ export const verifyStylesGeneralAccordion = (
commonWidgetSelector.boxShadowDefaultParam,
boxShadowParameter
);
selectColourFromColourPicker(commonWidgetText.boxShadowColor, boxShadowColor);
selectColourFromColourPicker(
commonWidgetText.boxShadowColor,
boxShadowColor,
index
);
verifyBoxShadowCss(widgetName, boxShadowColor, boxShadowParameter);
};
@ -322,11 +335,14 @@ export const addTextWidgetToVerifyValue = (customfunction) => {
export const verifyTooltip = (widgetSelector, message) => {
cy.forceClickOnCanvas();
cy.get(widgetSelector).click();
cy.get(widgetSelector)
.trigger("mouseover", { timeout: 2000 })
.trigger("mouseover")
.then(() => {
cy.get(commonWidgetSelector.tooltipLabel).should("have.text", message);
cy.get(commonWidgetSelector.tooltipLabel)
.last()
.should("have.text", message);
});
};

View file

@ -1,7 +1,6 @@
import { commonSelectors } from "Selectors/common";
import { dashboardSelector } from "Selectors/dashboard";
import { dashboardText } from "Texts/dashboard";
import { loginSelectors } from "Selectors/login";
import { commonText } from "Texts/common";
import {
viewAppCardOptions,
@ -12,9 +11,9 @@ import {
export const login = () => {
cy.visit("/");
cy.clearAndType(loginSelectors.emailField, "dev@tooljet.io");
cy.clearAndType(loginSelectors.passwordField, "password");
cy.get(loginSelectors.signInButton).click();
cy.clearAndType(commonSelectors.workEmailInputField, "dev@tooljet.io");
cy.clearAndType(commonSelectors.passwordInputField, "password");
cy.get(commonSelectors.loginButton).click();
};
export const modifyAndVerifyAppCardIcon = (appName) => {

View file

@ -0,0 +1,14 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
export const verifyCouldnotConnectWithAlert = (dangerText) => {
cy.get(postgreSqlSelector.connectionFailedText, {
timeout: 10000,
}).verifyVisibleElement("have.text", postgreSqlText.couldNotConnect, {
timeout: 5000,
});
cy.get(postgreSqlSelector.dangerAlertNotSupportSSL).verifyVisibleElement(
"contain.text",
dangerText
);
};

View file

@ -1,43 +0,0 @@
import { loginSelectors } from "Selectors/login";
import { loginTexts } from "Texts/login";
import { path } from "Texts/common";
export const loginPageElements = () => {
cy.url().should("include", path.loginPath);
cy.get(loginSelectors.logo).should("be.visible");
cy.get(loginSelectors.cardTitle).verifyVisibleElement(
"have.text",
loginTexts.cardTitle
);
cy.get(loginSelectors.emailLabel).verifyVisibleElement(
"have.text",
loginTexts.emailLabel
);
cy.get(loginSelectors.passwordLabel)
.should(($el) => {
expect($el.contents().first().text().trim()).to.eq(
loginTexts.passwordLabel
);
})
.should("be.visible");
cy.get(loginSelectors.forgotPassword).verifyVisibleElement(
"have.text",
loginTexts.forgotPassword
);
cy.get(loginSelectors.showPassword).should(
"have.text",
loginTexts.showPassword
);
cy.get(loginSelectors.signUpText).should("be.visible");
cy.get(loginSelectors.checkBox).check();
cy.get(loginSelectors.checkBox).uncheck();
cy.get(loginSelectors.signUpText)
.should(($el) => {
expect($el.contents().first().text().trim()).to.eq(loginTexts.signUpText);
})
.should("be.visible");
cy.get(loginSelectors.signUpLink).verifyVisibleElement(
"have.text",
loginTexts.signUpLink
);
};

View file

@ -3,7 +3,6 @@ import { ssoSelector } from "Selectors/manageSSO";
import { ssoText } from "Texts/manageSSO";
import * as common from "Support/utils/common";
import { commonText } from "Texts/common";
import { loginSelectors } from "Selectors/login";
import { dashboardSelector } from "Selectors/dashboard";
export const generalSettings = () => {
@ -286,7 +285,7 @@ export const passwordLoginVisible = () => {
export const workspaceLogin = (workspaceName) => {
cy.clearAndType(commonSelectors.workEmailInputField, "dev@tooljet.io");
cy.clearAndType(commonSelectors.passwordInputField, "password");
cy.get(loginSelectors.signInButton).click();
cy.get(commonSelectors.loginButton).click();
cy.get(commonSelectors.homePageLogo).should("be.visible");
cy.get(dashboardSelector.modeToggle, { timeout: 10000 }).should("be.visible");
cy.get(commonSelectors.workspaceName).verifyVisibleElement(

View file

@ -60,15 +60,23 @@ export const fillConnectionForm = (data) => {
cy.get(postgreSqlSelector.buttonSave).click();
};
export const fillDataSourceTextField = (fieldName, placeholder, input) => {
export const fillDataSourceTextField = (
fieldName,
placeholder,
input,
assertionType = "have",
args
) => {
cy.get(`[data-cy="label-${cyParamName(fieldName)}"]`).should(
"have.text",
`${assertionType}.text`,
fieldName
);
cy.get(`[data-cy="${cyParamName(fieldName)}-text-field"]`)
.invoke("attr", "placeholder")
.should("eq", placeholder.replace(/\u00a0/g, " "));
cy.clearAndType(`[data-cy="${cyParamName(fieldName)}-text-field"]`, input);
cy.get(`[data-cy="${cyParamName(fieldName)}-text-field"]`)
.clear()
.type(input, args);
};
export const openQueryEditor = (dataSourceName) => {

View file

@ -12,7 +12,12 @@ DEPLOYMENT_PLATFORM=ec2
# ToolJet Database
ENABLE_TOOLJET_DB=false
TOOLJET_DB=tooljet_db
TOOLJET_DB_USER=
TOOLJET_DB_HOST=
TOOLJET_DB_PASS=
PGRST_HOST=localhost:3001
PGRST_SERVER_PORT=3001
PGRST_JWT_SECRET=
PGRST_DB_URI=

View file

@ -36,7 +36,6 @@ then
fi
sudo npm --prefix server run db:setup:prod
sudo npm --prefix server run db:seed:prod
if sudo systemctl start nest
then

View file

@ -51,6 +51,11 @@ build {
destination = "/tmp/setup_app"
}
provisioner "file" {
source = "postgrest.service"
destination = "/tmp/postgrest.service"
}
provisioner "shell" {
script = "setup_machine.sh"
}

View file

@ -34,7 +34,13 @@ COPY ./server/ ./server/
RUN npm install -g @nestjs/cli
RUN npm --prefix server run build
FROM node:14.17.3-buster
FROM debian:11
RUN apt-get update -yq \
&& apt-get install curl gnupg zip -yq \
&& curl -fsSL https://deb.nodesource.com/setup_14.17.3 | bash \
&& apt-get install nodejs npm -yq \
&& apt-get clean -y
ENV NODE_ENV=production
ENV NODE_OPTIONS="--max-old-space-size=4096"
@ -46,6 +52,7 @@ RUN apt-get update && \
# Install Instantclient Basic Light Oracle and Dependencies
WORKDIR /opt/oracle
RUN wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip && \
unzip instantclient-basiclite-linuxx64.zip && rm -f instantclient-basiclite-linuxx64.zip && \
cd /opt/oracle/instantclient* && rm -f *jdbc* *occi* *mysql* *mql1* *ipc1* *jar uidrvci genezi adrci && \
@ -76,5 +83,5 @@ RUN chgrp -R 0 /app && chmod -R g=u /app
WORKDIR /app
# Dependencies for scripts outside nestjs
RUN npm install dotenv@10.0.0 joi@17.4.1
ENTRYPOINT ["./server/entrypoint.sh"]

View file

@ -25,7 +25,13 @@ RUN npm --prefix server install --only=production
COPY ./server/ ./server/
RUN npm --prefix server run build
FROM node:14.17.3-buster
FROM debian:11
RUN apt-get update -yq \
&& apt-get install curl gnupg zip -yq \
&& curl -fsSL https://deb.nodesource.com/setup_14.17.3 | bash \
&& apt-get install nodejs npm -yq \
&& apt-get clean -y
ENV NODE_ENV=production
ENV NODE_OPTIONS="--max-old-space-size=4096"

View file

@ -38,6 +38,8 @@ The App (which credentials are provided) needs to be installed in the workspace
1. **List members**
2. **Send message**
2. **List messages**
### List members
This operation will return the data of all the members in your slack workspace.
@ -56,6 +58,8 @@ This operation will send/post the message to a specified channel or posting to d
| :--- | :--- |
| Channel | The channel ID or user ID to post the message to. |
| Message | The message to post. |
| Limit | The maximum number of messages to return. |
| Cursor | A cursor value returned by a previous call to list messages. |
<div style={{textAlign: 'center'}}>
@ -63,5 +67,19 @@ This operation will send/post the message to a specified channel or posting to d
</div>
### List messages
This operation will get the messages from a specified channel.
| Property | Description |
| :--- |:----------------------------------------|
| Channel | The channel ID to get the messages from |
<div style={{textAlign: 'center'}}>
![ToolJet - Data source - Slack](/img/datasource-reference/slack/listmessages.png)
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 MiB

After

Width:  |  Height:  |  Size: 8.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

View file

@ -26,6 +26,6 @@ You will be redirected to the visual app editor once the app has been created. C
The main components of an app:
- **[Widgets](https://docs.tooljet.com/docs/tutorial/adding-widget)** - UI components such as tables, buttons, dropdowns.
- **[Widgets](https://docs.tooljet.com/docs/tutorial/adding-widget)** - UI components such as tables, buttons, and dropdowns etc.
- **[Data sources](https://docs.tooljet.com/docs/tutorial/adding-a-datasource)** - ToolJet can connect to databases, APIs and external services to fetch and modify data.
- **[Queries](https://docs.tooljet.com/docs/tutorial/building-queries)** - Queries are used to access the connected data sources.
- **[Queries](https://docs.tooljet.com/docs/tutorial/building-queries)** - Queries are used to access the connected data sources.

View file

@ -39,7 +39,7 @@ ToolJet comes with flexible components to group other components together, such
### Hide or Disable Components
Hide or Disable a component by settting it's **Visibility** or **Disabled** property to `true`. Click on the component handle to open **config inspector** on right side. These values can also evaluate to true based on a truthy value. For example, you can use the property of one component to toggle the Visibility property of another component dynamically, you just need to write a conditional statement.
Hide or Disable a component by setting its **Visibility** or **Disabled** property to `true`. Click on the component handle to open **config inspector** on right side. These values can also evaluate to true based on a truthy value. For example, you can use the property of one component to toggle the Visibility property of another component dynamically, you just need to write a conditional statement.
For example: We want to disable a button when a checkbox is checked so we can simple use `{{components.checkbox1.value}}` in **Disable** property of the button. `{{components.checkbox1.value}}` evaluates to `true` when the checkbox is checked, and false when unchecked.

View file

@ -9,7 +9,7 @@ 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 componenets, queries or variables, and **[debug](#debugger)** the errors.
- **[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.
- **[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

View file

@ -21,7 +21,7 @@ Query Manager will list all the queries that has been created in the application
### Search
On the top of the query manager is search box that can be used to search for a specif query.
On the top of the query manager is search box that can be used to search for a specific query.
<div style={{textAlign: 'center'}}>

View file

@ -100,7 +100,7 @@ Comment anywhere on the canvas and collaborate with other users in the workspace
Share your applications with a unique URL generated automatically or edit the URL slug to personalize it.
- When **Make the application public** is off and URL is shared then the users will have to login to ToolJet to use the application. Toggle on the option then anyone on the internet will be able to access the application without logging in to ToolJet.
- ToolJet generates the **Embedded link** which can be used to embedd application on the webpages.
- ToolJet generates the **Embedded link** which can be used to embed application on the webpages.
<div style={{textAlign: 'center'}}>

View file

@ -101,18 +101,7 @@ Please find more information [here](https://docs.docker.com/desktop/windows/wsl/
```bash
docker-compose up
```
6. ToolJet server is built using NestJS and the data such as application definitions are persisted on a postgres database. You can run the below command to seed the database.
```bash
docker-compose exec server npm run db:seed
```
7. ToolJet should now be served locally at `http://localhost:8082`. You can login using the default user created.
```
email: dev@tooljet.io
password: password
```
ToolJet should now be served locally at `http://localhost:8082`.
8. To shut down the containers,
```bash

View file

@ -14,7 +14,7 @@ You can write custom Python code to interact with components and queries. To do
#### Example: Using Python code to trigger component specific actions
- Let's drag a **button** and a **text** widget onto the canvas. We will set a text on the text component and trigger button click event from the Python query.
- Click on the `+` on the query panel to create a query and select **Run JavaScript code** from the available datasources
- Click on the `+` on the query panel to create a query and select **Run Python code** from the available datasources
- Let's write the code in **Python Editor** and save the query:
```python
@ -52,4 +52,4 @@ You can also write custom Python code to get the data from **External APIs** and
:::info
Issues with writing custom Python code? Ask in our [Slack community](https://www.tooljet.com/slack).
:::
:::

View file

@ -27,7 +27,7 @@ When you're building an internal tool, there are a lot of tools and frameworks a
- **Open-Source**: ToolJet is Open-Source, you can go through the ToolJet codebase on **[GitHub](https://github.com/ToolJet/ToolJet)** or you can **deploy ToolJet on your infrastructure**.
- **Full-stack platform**: ToolJet has a **[built-in database](/docs/tooljet-database)**, **[External datasources](/docs/data-sources/airtable)**, and a frontend builder so you can build a full-stack app right inside it. ToolJet comes with Custom Component for importing your own **react components** and the ability to write custom **JavaScript** and **Python** code.
- **Extensible**: Didn't find the **component** or **datasource** that fit your application's requirements? You can always build your own **component** and **datasource** using our **plugin developement kit**.
- **Extensible**: Didn't find the **component** or **datasource** that fit your application's requirements? You can always build your own **component** and **datasource** using our **plugin development kit**.
- **Powerful Apps**: With ToolJet, developers can quickly build powerful custom internal tools for their Support, Operations and Sales teams. Build CRUD apps, Dashboards, Admin Panels, CRMs and much more.
-->
@ -56,7 +56,7 @@ When you're building an internal tool, there are a lot of tools and frameworks a
There are a few different ways to set up ToolJet depending on how you intend to use it:
- **[ToolJet Cloud](https://www.tooljet.com)**: hosted solution, just sign-up for free and start building apps in seconds.
- **[Deploy on premise](/docs/setup/)**: recommended method for production or customized use cases. You'll find Server setup guides for popular platforms (AWS, GCP, Kubernetes etc) and one-click deployement guides (Heroku, DigitalOcean etc).
- **[Deploy on premise](/docs/setup/)**: recommended method for production or customized use cases. You'll find Server setup guides for popular platforms (AWS, GCP, Kubernetes etc) and one-click deployment guides (Heroku, DigitalOcean etc).
- **[Try ToolJet on local machine](/docs/setup/try-tooljet/)**: the fastest way to try out ToolJet on your computer using docker.
:::info
@ -159,7 +159,7 @@ ToolJet application's User interface is constructed using Components like Tables
ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **Datasource Catalog** to learn more.
:::
2. Choose a **Table** from the dropdown, Select the **List rows** option from the **Operation** dropdown, You can leave other query parameters. Scroll down and enable **Run this query on application load** - this will trigger the query when the app is laoded.
2. Choose a **Table** from the dropdown, Select the **List rows** option from the **Operation** dropdown, You can leave other query parameters. Scroll down and enable **Run this query on application load** - this will trigger the query when the app is loaded.
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'}}>

View file

@ -0,0 +1,98 @@
---
id: import-external-libraries-using-runpy
title: Import external libraries using RunPy
---
ToolJet allows you to utilize python packages in your app by importing them using the [RunPy query](/docs/data-sources/run-py).
In this how-to guide, we will import a few packages and use it in the application.
:::caution Unsupported modules
The modules that are not currently supported in Pyodide are those that have C or C++ extensions that rely on system libraries. These modules cannot be used in Pyodide because it runs in a web browser, which does not have access to the underlying system libraries that the C or C++ extensions rely on. Additionally, Pyodide uses a version of Python that has been compiled to WebAssembly, which does not support the same system calls as a regular version of Python. Therefore, any module that requires access to system libraries or system calls will not work in Pyodide.
:::
- Create a new application and then create a new RunPy query from the query panel.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/import-python/runpy.png" alt="Import external libraries using RunPy" />
</div>
- Let's write some code for importing packages. We will first import the micropip which is a package installer for Python and then we will install the `Pandas` and `NumPy` using micropip. **Run** the query to install the packages.
```python
import micropip
await micropip.install('pandas')
await micropip.install('numpy')
```
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/import-python/installing.png" alt="Import external libraries using RunPy"/>
</div>
:::tip
Enable the **Run this query on application load?** option to make the packages available throughout the application.
:::
## Examples
### Array of random numbers of using NumPy
- Let's create a **RunPy** query that will use **random** module from the **NumPy** package and the query will generate array of random numbers.
```python
from numpy import random
x = random.binomial(n=10, p=0.5, size=10)
print(x)
```
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/import-python/random.gif" alt="Import external libraries using RunPy"/>
</div>
:::info
You can check the output on the browser's console.
:::
### Parse CSV data using
- Let's create a RunPy query that will parse the data from the csv file. In this query we will use `StringIO`, `csv`, and `Pandas` module.
```python
from io import StringIO
import csv
import pandas as pd
scsv = components.filepicker1.file[0].content
f = StringIO(scsv)
reader = csv.reader(f, delimiter=',')
df = pd.DataFrame(reader)
print(df.info())
print(df)
```
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/import-python/csvparse.png" alt="Import external libraries using RunPy"/>
</div>
- Add a file picker component on the canvas and set a event handler for **On file loaded** event to **Run Query** that we created for parsing the data.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/import-python/event.png" alt="Import external libraries using RunPy"/>
</div>
- Finally, let's load a csv file on the file picker and check the output by the RunPy query on the browser console.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/import-python/console.gif" alt="Import external libraries using RunPy"/>
</div>

View file

@ -84,7 +84,7 @@ In this how-to guide, we will be building a simple application that will leverag
- Now, this application can be used to load the data from the Google Sheet and the form can be used to append more records to the sheet.
:::tip
- Make sure to enable **Run query on page load?** option of the **read** query to populate the table everytime the app is laoded
- You can also add a event handler on the **append** query to run the **read** query when **append** is succesfull, this will update the table data when the append is done
- Make sure to enable **Run query on page load?** option of the **read** query to populate the table everytime the app is loaded
- You can also add a event handler on the **append** query to run the **read** query when **append** is successful, this will update the table data when the append is done
- Learn more about the connecting Google sheet datasource and the CRUD **operations** available [here](/docs/data-sources/google.sheets).
:::

View file

@ -125,7 +125,7 @@ If you intend to use this feature, you'd have to set up and deploy PostgREST ser
<img className="screenshot-full" src="/img/cloud-run/port-and-capacity-postgrest.png" alt="port-and-capacity-postgrest" />
</div>
5. Under environmental variable please add correponding Tooljet database env variables. You can also refer [env variable](/docs/setup/env-vars#tooljet-database).
5. Under environmental variable please add corresponding Tooljet database env variables. You can also refer [env variable](/docs/setup/env-vars#tooljet-database).
6. Please go to connection tab. Under Cloud SQL instance please select the PostgreSQL database which you have set-up for Tooljet application or the separate PostgreSQL database created respective to Tooljet Database from the drop-down option.

View file

@ -36,7 +36,7 @@ If this parameter is not specified then PostgREST refuses authentication request
| PGRST_LOG_LEVEL | `info` |
:::info
Please make sure that DB_URI is given in the format `postgrest://[USERNAME]:[PASSWORD]@[HOST]:[PORT]/[DATABASE]`
Please make sure that DB_URI is given in the format `postgres://[USERNAME]:[PASSWORD]@[HOST]:[PORT]/[DATABASE]`
:::
#### Additional ToolJet server configuration

View file

@ -30,7 +30,7 @@ You can open the **Pages Panel** by clicking on the **Pages** icon on the left s
### Add Page
On the header of the Pages Manger, the **+** button that allows you to add more pages to your application
On the header of the Pages Manager, the **+** button that allows you to add more pages to your application
<div style={{textAlign: 'center'}}>
@ -45,7 +45,7 @@ On clicking the **+** button, a new page will be added, enter the name for the p
</div>
### Setttings
### Settings
From **Settings**, you can hide the **page navigation sidebar** in viewer mode, by enabling the **Disable Menu** option.
<div style={{textAlign: 'center'}}>

View file

@ -13,7 +13,7 @@ Components can be dragged and dropped from the Component Library(from the right
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/widgets/overview/dragv2.gif" alt="Componenets: Overview" />
<img className="screenshot-full" src="/img/widgets/overview/dragv2.gif" alt="Components: Overview" />
</div>
@ -23,7 +23,7 @@ For moving the **multiple components** at once, simply **shift+click**, to selec
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/widgets/overview/selectv2.gif" alt="Componenets: Overview" />
<img className="screenshot-full" src="/img/widgets/overview/selectv2.gif" alt="Components: Overview" />
</div>
@ -31,7 +31,7 @@ You can also create a selection triangle and move multiple components together b
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/widgets/overview/dragselv2.gif" alt="Componenets: Overview" />
<img className="screenshot-full" src="/img/widgets/overview/dragselv2.gif" alt="Components: Overview" />
</div>
@ -45,7 +45,7 @@ Each Component can be modified and styled from the Properties Panel such as the
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/widgets/overview/props.png" alt="Componenets: Overview" />
<img className="screenshot-full" src="/img/widgets/overview/props.png" alt="Components: Overview" />
</div>
@ -59,7 +59,7 @@ Check all the available Actions **[here](/docs/category/actions-reference)**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/widgets/overview/events.png" alt="Componenets: Overview" />
<img className="screenshot-full" src="/img/widgets/overview/events.png" alt="Components: Overview" />
</div>
@ -67,7 +67,7 @@ Check all the available Actions **[here](/docs/category/actions-reference)**.
Bindings allow you to get dynamic data into the components. Anything inside of **`{{}}`** is evaluated as a JavaScript expression in ToolJet.
Any arbitary JavaScript code can be written inside **`{{}}`**:
Any arbitrary JavaScript code can be written inside **`{{}}`**:
```js
{{(function () {
<your_javascript_code_here>

View file

@ -1,5 +1,5 @@
---
id: star
id: star-rating
title: Star rating
---
# Star rating
@ -82,4 +82,4 @@ Toggle on or off to control the visibility of the widget. You can programmatical
### Disable
This is `off` by default, toggle `on` the switch to lock the widget and make it non-functional. You can also programmatically set the value by clicking on the `Fx` button next to it. If set to `{{true}}`, the widget will be locked and becomes non-functional. By default, its value is set to `{{false}}`.
This is `off` by default, toggle `on` the switch to lock the widget and make it non-functional. You can also programmatically set the value by clicking on the `Fx` button next to it. If set to `{{true}}`, the widget will be locked and becomes non-functional. By default, its value is set to `{{false}}`.

View file

@ -128,7 +128,7 @@
"widgets/range-slider",
"widgets/rich-text-editor",
"widgets/spinner",
"widgets/star",
"widgets/star-rating",
"widgets/statistics",
"widgets/steps",
"widgets/svg-image",
@ -283,6 +283,7 @@
"how-to/access-cellvalue-rowdata",
"how-to/bulk-update-multiple-rows",
"how-to/access-currentuser",
"how-to/import-external-libraries-using-runpy",
"how-to/run-actions-from-runjs",
"how-to/run-query-at-specified-intervals",
"how-to/access-users-location",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -77,6 +77,7 @@ export const CreateVersion = ({
type="text"
onChange={(e) => setVersionName(e.target.value)}
className="form-control"
data-cy="version-name-input-field"
placeholder={t('editor.appVersionManager.enterVersionName', 'Enter version name')}
disabled={isCreatingVersion}
value={versionName}
@ -88,8 +89,10 @@ export const CreateVersion = ({
</div>
<div className="mb-4 pb-2">
<label className="form-label">{t('editor.appVersionManager.createVersionFrom', 'Create version from')}</label>
<div className="ts-control">
<label className="form-label" data-cy="create-version-from-label">
{t('editor.appVersionManager.createVersionFrom', 'Create version from')}
</label>
<div className="ts-control" data-cy="create-version-from-input-field">
<Select
options={options}
defaultValue={options[options.length - 1]}
@ -131,6 +134,7 @@ export const CreateVersion = ({
<div className="col d-flex justify-content-end">
<button
className="btn mx-2"
data-cy="cancel-button"
onClick={() => {
closeCreateVersionModalPrompt();
setShowCreateAppVersion(false);
@ -139,7 +143,11 @@ export const CreateVersion = ({
>
{t('globals.cancel', 'Cancel')}
</button>
<button className={`btn btn-primary ${isCreatingVersion ? 'btn-loading' : ''}`} type="submit">
<button
className={`btn btn-primary ${isCreatingVersion ? 'btn-loading' : ''}`}
data-cy="create-new-version-button"
type="submit"
>
<svg
className="icon"
width="21"

View file

@ -69,7 +69,7 @@ const Menu = (props) => {
const SingleValue = ({ selectProps, data }) => {
return (
<div className="d-inline-flex align-items-center">
<div className="d-inline-flex align-items-center" data-cy="app-version-label">
<svg className="me-2" width="35" height="21" viewBox="0 0 35 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
@ -82,7 +82,10 @@ const SingleValue = ({ selectProps, data }) => {
fill="#E03177"
/>
</svg>
<div className={cx('app-version-name', { 'color-light-green': selectProps.value.isReleasedVersion })}>
<div
className={cx('app-version-name', { 'color-light-green': selectProps.value.isReleasedVersion })}
data-cy={`${selectProps.value?.appVersionName}-current-version-text`}
>
{selectProps.value?.appVersionName}
</div>
</div>
@ -112,6 +115,7 @@ export const CustomSelect = ({ ...props }) => {
<Select
width={'100%'}
classNamePrefix="custom-version-selector"
data-cy={`test-version-selector`}
hasSearch={false}
components={{ Menu, SingleValue }}
setShowEditAppVersion={setShowEditAppVersion}

View file

@ -120,7 +120,7 @@ export const AppVersionsManager = function ({
};
return (
<div className="app-versions-selector">
<div className="app-versions-selector" data-cy="app-version-selector">
<CustomSelect
isLoading={appVersionStatus === 'loading'}
options={options}

View file

@ -331,6 +331,7 @@ export const Box = function Box({
mode={mode}
resetComponent={() => setResetStatus(true)}
childComponents={childComponents}
dataCy={`draggable-widget-${String(component.name).toLowerCase()}`}
></ComponentToRender>
) : (
<></>

View file

@ -43,7 +43,7 @@ const Content = ({ notifications, loading, darkMode }) => {
>
<div className="d-flex justify-content-between">
<span className="comment-notification-user">
{`${comment.user?.firstName} ${comment.user?.lastName}`}{' '}
{`${comment.user?.firstName} ${comment.user?.lastName ?? ''}`}{' '}
</span>
<div className={`comment-notification-count ms-auto ${darkMode && 'text-light'}`}>
{moment(comment.createdAt).fromNow()}

View file

@ -3,7 +3,7 @@ import cx from 'classnames';
var tinycolor = require('tinycolor2');
export const Button = function Button(props) {
const { height, properties, styles, fireEvent, registerAction, component, id } = props;
const { height, properties, styles, fireEvent, registerAction, component, id, dataCy } = props;
const { backgroundColor, textColor, borderRadius, loaderColor, disabledState, borderColor } = styles;
const [label, setLabel] = useState(properties.text);
@ -101,7 +101,7 @@ export const Button = function Button(props) {
onMouseOver={() => {
fireEvent('onHover');
}}
data-cy={`draggable-widget-${String(component.name).toLowerCase()}`}
data-cy={dataCy}
type="default"
>
{label}

View file

@ -1,6 +1,14 @@
import React, { useEffect, useState } from 'react';
export const ButtonGroup = function Button({ height, properties, styles, fireEvent, setExposedVariable, darkMode }) {
export const ButtonGroup = function Button({
height,
properties,
styles,
fireEvent,
setExposedVariable,
darkMode,
dataCy,
}) {
const { values, labels, label, defaultSelected, multiSelection } = properties;
const {
backgroundColor,
@ -60,7 +68,7 @@ export const ButtonGroup = function Button({ height, properties, styles, fireEve
}
};
return (
<div className="widget-buttongroup" style={{ height }}>
<div className="widget-buttongroup" style={{ height }} data-cy={dataCy}>
{label && <p className={`widget-buttongroup-label ${darkMode && 'text-light'}`}>{label}</p>}
<div>
{data?.map((item, index) => (

View file

@ -37,6 +37,7 @@ export const Calendar = function ({
removeComponent,
setExposedVariable,
exposedVariables,
dataCy,
}) {
const style = { height };
const resourcesParam = properties.resources?.length === 0 ? {} : { resources: properties.resources };
@ -124,7 +125,7 @@ export const Calendar = function ({
}
return (
<div id={id} style={{ display: styles.visibility ? 'block' : 'none' }}>
<div id={id} style={{ display: styles.visibility ? 'block' : 'none' }} data-cy={dataCy}>
<ReactCalendar
className={`calendar-widget
${darkMode ? 'dark-mode' : ''}

View file

@ -6,7 +6,7 @@ import createPlotlyComponent from 'react-plotly.js/factory';
import { isJson } from '@/_helpers/utils';
const Plot = createPlotlyComponent(Plotly);
export const Chart = function Chart({ width, height, darkMode, properties, styles }) {
export const Chart = function Chart({ width, height, darkMode, properties, styles, dataCy }) {
const [loadingState, setLoadingState] = useState(false);
const { padding, visibility, disabledState } = styles;
@ -124,7 +124,7 @@ export const Chart = function Chart({ width, height, darkMode, properties, style
);
return (
<div data-disabled={disabledState} style={computedStyles}>
<div data-disabled={disabledState} style={computedStyles} data-cy={dataCy}>
{loadingState === true ? (
<div style={{ width }} className="p-2 loader-main-container">
<center>

View file

@ -8,6 +8,7 @@ export const Checkbox = function Checkbox({
setExposedVariable,
registerAction,
darkMode,
dataCy,
}) {
const defaultValueFromProperties = properties.defaultValue ?? false;
const [defaultValue, setDefaultvalue] = React.useState(defaultValueFromProperties);
@ -43,7 +44,12 @@ export const Checkbox = function Checkbox({
);
return (
<div data-disabled={disabledState} className="row py-1" style={{ height, display: visibility ? '' : 'none' }}>
<div
data-disabled={disabledState}
className="row py-1"
style={{ height, display: visibility ? '' : 'none' }}
data-cy={dataCy}
>
<div className="col px-1 py-0 mt-0">
<label className="mx-1 form-check form-check-inline">
<input

View file

@ -2,7 +2,7 @@ import React from 'react';
import { CircularProgressbar } from 'react-circular-progressbar';
import 'react-circular-progressbar/dist/styles.css';
export const CircularProgressBar = function CircularProgressBar({ height, properties, styles }) {
export const CircularProgressBar = function CircularProgressBar({ height, properties, styles, dataCy }) {
const { text, progress } = properties;
const { visibility, color, textColor, textSize, strokeWidth, counterClockwise, circleRatio } = styles;
@ -11,7 +11,7 @@ export const CircularProgressBar = function CircularProgressBar({ height, proper
};
return (
<div style={computedStyles}>
<div style={computedStyles} data-cy={dataCy}>
<CircularProgressbar
value={progress}
text={text}

View file

@ -10,7 +10,7 @@ import 'codemirror/theme/duotone-light.css';
import 'codemirror/theme/monokai.css';
import { onBeforeChange, handleChange } from '../CodeBuilder/utils';
export const CodeEditor = ({ height, darkMode, properties, styles, exposedVariables, setExposedVariable }) => {
export const CodeEditor = ({ height, darkMode, properties, styles, exposedVariables, setExposedVariable, dataCy }) => {
const { enableLineNumber, mode, placeholder } = properties;
const { visibility, disabledState } = styles;
@ -39,7 +39,7 @@ export const CodeEditor = ({ height, darkMode, properties, styles, exposedVariab
}
return (
<div data-disabled={disabledState} style={editorStyles}>
<div data-disabled={disabledState} style={editorStyles} data-cy={dataCy}>
<div
className={`code-hinter codehinter-default-input code-editor-widget`}
style={{

View file

@ -10,6 +10,7 @@ export const ColorPicker = function ({
height,
registerAction,
fireEvent,
dataCy,
}) {
const { visibility } = styles;
const defaultColor = properties.defaultColor;
@ -114,7 +115,7 @@ export const ColorPicker = function ({
: { display: 'none' };
return (
<div style={baseStyle} className="form-control">
<div style={baseStyle} className="form-control" data-cy={dataCy}>
<div className="d-flex h-100 justify-content-between align-items-center" onClick={() => setShowColorPicker(true)}>
<span>{color}</span>
{!(color === `Invalid Color`) && <div style={backgroundColorDivStyle}></div>}

View file

@ -11,6 +11,7 @@ export const Container = function Container({
removeComponent,
styles,
darkMode,
dataCy,
}) {
const { visibility, disabledState, borderRadius, borderColor } = styles;
const backgroundColor =
@ -30,6 +31,7 @@ export const Container = function Container({
data-disabled={disabledState}
className="jet-container"
id={id}
data-cy={dataCy}
ref={parentRef}
style={computedStyles}
onClick={(e) => {

View file

@ -3,7 +3,8 @@ import { isEqual } from 'lodash';
import iframeContent from './iframe.html';
export const CustomComponent = (props) => {
const { height, properties, styles, id, setExposedVariable, exposedVariables, fireEvent, dataQueries } = props;
const { height, properties, styles, id, setExposedVariable, exposedVariables, fireEvent, dataQueries, dataCy } =
props;
const { visibility } = styles;
const { code, data } = properties;
const [customProps, setCustomProps] = useState(data);
@ -93,7 +94,7 @@ export const CustomComponent = (props) => {
};
return (
<div className="card" style={{ display: visibility ? '' : 'none', height }}>
<div className="card" style={{ display: visibility ? '' : 'none', height }} data-cy={dataCy}>
<iframe
srcDoc={iframeContent}
style={{ width: '100%', height: '100%', border: 'none' }}

View file

@ -15,6 +15,7 @@ export const Datepicker = function Datepicker({
id,
darkMode,
fireEvent,
dataCy,
}) {
const { enableTime, enableDate, defaultValue, disabledDates } = properties;
const format = typeof properties.format === 'string' ? properties.format : '';
@ -80,7 +81,7 @@ export const Datepicker = function Datepicker({
<div
data-disabled={disabledState}
className={`datepicker-widget ${darkMode && 'theme-dark'}`}
data-cy={`draggable-widget-${String(component.name).toLowerCase()}`}
data-cy={dataCy}
style={{
height,
display: visibility ? '' : 'none',

View file

@ -13,6 +13,7 @@ export const DaterangePicker = function DaterangePicker({
width,
darkMode,
fireEvent,
dataCy,
}) {
const { borderRadius, visibility, disabledState } = styles;
const { defaultStartDate, defaultEndDate } = properties;
@ -66,6 +67,7 @@ export const DaterangePicker = function DaterangePicker({
<div
className={`daterange-picker-widget ${darkMode && 'theme-dark'} p-0`}
style={{ height, display: visibility ? '' : 'none' }}
data-cy={dataCy}
>
<DateRangePicker
disabled={disabledState}

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