Added automation for Rest API all methods (#12935)

* add rest api auth

* add content-type scenario

* fixed failed cypress specs

* update version spec
This commit is contained in:
Mekhla Asopa 2025-05-27 13:20:39 +05:30 committed by GitHub
parent bd3b21ce3e
commit d7a5e07ff2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 708 additions and 283 deletions

View file

@ -52,7 +52,7 @@ Cypress.Commands.add("apiCreateGDS", (url, name, kind, options) => {
log: false;
}
expect(response.status).to.equal(201);
Cypress.env(`${kind}`, response.body.id);
Cypress.env(`${name}`, response.body.id);
Cypress.log({
name: "Create Data Source",
@ -80,13 +80,14 @@ Cypress.Commands.add("apiFetchDataSourcesId", () => {
Cypress.log({
name: "DS Fetch",
displayName: "Data Sources Fetched",
message: dataSources.map(ds => `\nKind: '${ds.kind}', Name: '${ds.id}'`).join(','),
message: dataSources
.map((ds) => `\nKind: '${ds.kind}', Name: '${ds.id}'`)
.join(","),
});
});
});
});
Cypress.Commands.add("apiCreateApp", (appName = "testApp") => {
cy.window({ log: false }).then((win) => {
win.localStorage.setItem("walkthroughCompleted", "true");
@ -168,7 +169,6 @@ Cypress.Commands.add(
Cypress.env("editingVersionId", responseData.editing_version.id);
Cypress.env("environmentId", responseData.editorEnvironment.id);
});
cy.get(componentSelector, { timeout: 10000 });
}
@ -221,21 +221,21 @@ Cypress.Commands.add(
const requestBody =
envVar === "Enterprise"
? {
email: userEmail,
firstName: userName,
groups: [],
lastName: "",
role: userRole,
userMetadata: metaData,
}
email: userEmail,
firstName: userName,
groups: [],
lastName: "",
role: userRole,
userMetadata: metaData,
}
: {
email: userEmail,
firstName: userName,
groups: [],
lastName: "",
role: userRole,
userMetadata: metaData,
};
email: userEmail,
firstName: userName,
groups: [],
lastName: "",
role: userRole,
userMetadata: metaData,
};
cy.getCookie("tj_auth_token").then((cookie) => {
cy.request(
@ -289,7 +289,9 @@ Cypress.Commands.add("apiAddQuery", (queryName, query, dataQueryId) => {
Cypress.Commands.add(
"apiAddQueryToApp",
(queryName, options, dsName, dsKind) => {
cy.log(`${Cypress.env("server_host")}/api/data-queries/data-sources/${Cypress.env(dsKind)}/versions/${Cypress.env("editingVersionId")}`)
cy.log(
`${Cypress.env("server_host")}/api/data-queries/data-sources/${Cypress.env(dsKind)}/versions/${Cypress.env("editingVersionId")}`
);
cy.getCookie("tj_auth_token", { log: false }).then((cookie) => {
const authToken = `tj_auth_token=${cookie.value}`;
const workspaceId = Cypress.env("workspaceId");
@ -737,3 +739,55 @@ Cypress.Commands.add("apiGetAppData", (appId = Cypress.env("appId")) => {
});
});
});
Cypress.Commands.add("apiDeleteGDS", (name) => {
const dataSourceId = Cypress.env(`${name}`);
cy.getCookie("tj_auth_token").then((cookie) => {
cy.request({
method: "DELETE",
url: `${Cypress.env("server_host")}/api/data-sources/${dataSourceId}`,
headers: {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
},
failOnStatusCode: false,
}).then((response) => {
console.log("Delete response:", response);
expect(response.status, "Delete status code").to.eq(200);
Cypress.log({
name: "Delete Data Source",
displayName: "Data source deleted",
message: `Name: '${name}' | ID: '${dataSourceId}'`,
});
});
});
});
Cypress.Commands.add(
"apiUpdateGDS",
({ name, options, envName = "development" }) => {
cy.getAuthHeaders().then((headers) => {
cy.apiGetEnvironments().then((environments) => {
const environment = environments.find((env) => env.name === envName);
const environmentId = environment.id;
const dataSourceId = Cypress.env(`${name}`);
cy.request({
method: "PUT",
url: `${Cypress.env("server_host")}/api/data-sources/${dataSourceId}?environment_id=${environmentId}`,
headers: headers,
body: {
name: name,
options: options,
},
}).then((response) => {
expect(response.status).to.equal(200);
cy.log(`Datasource "${name}" updated successfully.`);
});
});
});
}
);

View file

@ -28,7 +28,7 @@ export const dataSourceSelector = {
buttonTestConnection: '[data-cy="test-connection-button"]',
connectionFailedText: '[data-cy="test-connection-failed-text"]',
buttonSave: '[data-cy="db-connection-save-button"] > .tj-base-btn',
dangerAlertNotSupportSSL: '.go3958317564',
dangerAlertNotSupportSSL: ".go3958317564",
passwordTextField: '[data-cy="password-text-field"]',
textConnectionVerified: '[data-cy="test-connection-verified-text"]',
@ -102,6 +102,12 @@ export const dataSourceSelector = {
eventQuerySelectionField: '[data-cy="query-selection-field"]',
connectionAlertText: '[data-cy="connection-alert-text"]',
deleteDSButton: (datasourceName) => {
return `[data-cy="${cyParamName(datasourceName)}-delete-button"]`
return `[data-cy="${cyParamName(datasourceName)}-delete-button"]`;
},
labelFieldName: (fieldName) => {
return `[data-cy="${cyParamName(fieldName)}-field-label"]`;
},
dataSourceNameButton: (dataSourceName) => {
return `[data-cy="${cyParamName(dataSourceName)}-button"]`;
},
};

View file

@ -69,25 +69,57 @@ describe("Data source Airtable", () => {
});
it("Should verify the functionality of AirTable connection form.", () => {
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
fillDataSourceTextField(
airtableText.ApiKey,
airtableText.apikeyPlaceholder,
Cypress.env("airTable_apikey")
);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dsName}-airtable`,
"airtable",
[
{
key: "personal_access_token",
value: "Invalid access token",
encrypted: true,
},
]
);
cy.get(
`[data-cy="cypress-${data.dsName}-airtable-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-airtable`);
deleteDatasource(`cypress-${data.dsName}-airtable`);
dataSourceSelector.dataSourceNameButton(`cypress-${data.dsName}-airtable`)
)
.should("be.visible")
.click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(dataSourceSelector.connectionFailedText, {
timeout: 10000,
}).should("have.text", postgreSqlText.couldNotConnect);
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
"Authentication failed: Invalid personal access token"
);
cy.reload();
cy.apiUpdateGDS({
name: `cypress-${data.dsName}-airtable`,
options: [
{
key: "personal_access_token",
value: `${Cypress.env("airTable_apikey")}`,
encrypted: true,
},
],
});
cy.get(
dataSourceSelector.dataSourceNameButton(`cypress-${data.dsName}-airtable`)
)
.should("be.visible")
.click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.apiDeleteGDS(`cypress-${data.dsName}-airtable`);
});
it("Should able to run the query with valid conection", () => {
@ -96,30 +128,20 @@ describe("Data source Airtable", () => {
const airTable_tableName = Cypress.env("airtable_tableName");
const airTable_recordID = Cypress.env("airtable_recordId");
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
fillDataSourceTextField(
airtableText.ApiKey,
airtableText.apikeyPlaceholder,
airTable_apiKey
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dsName}-airtable`,
"airtable",
[
{
key: "personal_access_token",
value: `${airTable_apiKey}`,
encrypted: true,
},
]
);
cy.wait(1000);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-airtable-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-airtable`);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.apiCreateApp(`${data.dsName}-airtable-app`);
cy.openApp();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
@ -280,10 +302,9 @@ describe("Data source Airtable", () => {
commonSelectors.toastMessage,
`Query (${data.queryName}) completed.`
);
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-airtable`
);
cy.apiDeleteApp(`${data.dsName}-airtable-app`);
cy.apiDeleteGDS(`cypress-${data.dsName}-airtable`);
});
});
});

View file

@ -66,10 +66,9 @@ describe("Data source BigQuery", () => {
`cypress-${data.dataSourceName}-bigquery`
);
cy.get('[data-cy="label-private-key"]').verifyVisibleElement(
"have.text",
firestoreText.labelPrivateKey
);
cy.get(
dataSourceSelector.labelFieldName(firestoreText.labelPrivateKey)
).verifyVisibleElement("have.text", "Private key*");
cy.get(".datasource-edit-btn").should("be.visible");
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",
@ -98,7 +97,7 @@ describe("Data source BigQuery", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
bigqueryText.errorInvalidEmailId
);
@ -110,38 +109,30 @@ describe("Data source BigQuery", () => {
});
it("Should verify the functionality of BigQuery connection form.", () => {
selectAndAddDataSource(
"databases",
bigqueryText.bigQuery,
data.dataSourceName
);
fillDataSourceTextField(
firestoreText.privateKey,
bigqueryText.placehlderPrivateKey,
`${JSON.stringify(Cypress.env("bigquery_pvt_key"))}`,
"contain",
{ parseSpecialCharSequences: false, delay: 0 }
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-bigquery`,
"bigquery",
[
{
key: "private_key",
value: `${JSON.stringify(Cypress.env("bigquery_pvt_key"))}`,
encrypted: true,
},
]
);
cy.get(
dataSourceSelector.dataSourceNameButton(
`cypress-${data.dataSourceName}-bigquery`
)
)
.should("be.visible")
.click();
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.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dataSourceName}-bigquery-button"]`
).verifyVisibleElement(
"have.text",
`cypress-${data.dataSourceName}-bigquery`
);
deleteDatasource(`cypress-${data.dataSourceName}-bigquery`);
cy.apiDeleteGDS(`cypress-${data.dataSourceName}-bigquery`);
});
});

View file

@ -101,7 +101,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
"Invalid URL"
);

View file

@ -127,7 +127,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
"Invalid URL"
);

View file

@ -115,7 +115,7 @@ describe("Data source DynamoDB", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
dynamoDbText.errorMissingRegion
);

View file

@ -122,7 +122,7 @@ describe("Data source Elasticsearch", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
elasticsearchText.errorConnectionRefused
);

View file

@ -94,7 +94,7 @@ describe("Data source Firestore", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
firestoreText.errorGcpKeyCouldNotBeParsed
);

View file

@ -118,7 +118,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
"Invalid URL"
);

View file

@ -125,7 +125,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
// cy.get('[data-cy="connection-alert-text"]').should("be.visible")
// cy.get(dataSourceSelector.connectionAlertText).should("be.visible")
deleteDatasource(`cypress-${data.dataSourceName}-mariadb`);
});

View file

@ -129,7 +129,7 @@ describe("Data source MongoDB", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
mongoDbText.errorConnectionRefused
);
@ -164,7 +164,7 @@ describe("Data source MongoDB", () => {
}).verifyVisibleElement("have.text", postgreSqlText.couldNotConnect, {
timeout: 95000,
});
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
"Cannot read properties of null (reading '2')"
);

View file

@ -136,7 +136,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').should("be.visible");
cy.get(dataSourceSelector.connectionAlertText).should("be.visible");
deleteDatasource(`cypress-${data.dataSourceName}-postgresql`);
});

View file

@ -3,7 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { redisText } from "Texts/redis";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
fillDataSourceTextField,
@ -96,7 +96,7 @@ describe("Data source Redis", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
redisText.errorMaxRetries
);
@ -137,7 +137,7 @@ describe("Data source Redis", () => {
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
redisText.errorInvalidUserOrPassword
);
@ -152,7 +152,7 @@ describe("Data source Redis", () => {
"108299"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
redisText.errorPort
);
@ -170,7 +170,7 @@ describe("Data source Redis", () => {
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
redisText.errorInvalidUserOrPassword
);
@ -187,7 +187,7 @@ describe("Data source Redis", () => {
"redis"
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
redisText.errorInvalidUserOrPassword
);

View file

@ -329,9 +329,9 @@ describe("Data source Rest API", () => {
);
cy.contains("Save").click();
cy.verifyToastMessage(commonSelectors.toastMessage, "Data Source Saved");
deleteDatasource(`cypress-${data.dataSourceName}-restapi`);
cy.apiDeleteGDS(`cypress-${data.dataSourceName}-restapi`);
});
it("Should verify basic connection for Rest API", () => {
it("Should verify connection response for all methods", () => {
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-restapi`,
@ -367,88 +367,384 @@ describe("Data source Rest API", () => {
);
cy.reload();
cy.apiCreateApp(`${fake.companyName}-restAPI-App`);
cy.apiCreateApp(`${fake.companyName}-restAPI-CURD-App`);
cy.openApp();
createAndRunRestAPIQuery(
"get_restapi",
`cypress-${data.dataSourceName}-restapi`,
"GET",
"/api/users"
);
createAndRunRestAPIQuery(
"post_restapi",
`cypress-${data.dataSourceName}-restapi`,
"POST",
"",
[["Content-Type", "application/json"]],
[],
{
price: 200,
name: "Violin",
},
true,
"/api/users"
);
createAndRunRestAPIQuery({
queryName: "get_beeceptor_data",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "GET",
urlSuffix: "/api/users",
run: true,
});
createAndRunRestAPIQuery({
queryName: "post_restapi",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "POST",
headersList: [["Content-Type", "application/json"]],
rawBody: '{"price": 200,"name": "Violin"}',
urlSuffix: "/api/users",
expectedResponseShape: { price: 200, name: "Violin", id: true },
});
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
(postResponseID) => {
const id1 = postResponseID.id;
createAndRunRestAPIQuery(
"put_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"PUT",
"",
[["Content-Type", "application/json"]],
[],
{
price: 500,
name: "Guitar",
},
true,
`/api/users/${id1}`
);
}
);
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
(putResponseID) => {
const id2 = putResponseID.id;
createAndRunRestAPIQuery(
"patch_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"PATCH",
"",
[["Content-Type", "application/json"]],
[],
{ price: 999 },
true,
`/api/users/${id2}`
);
}
);
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
(patchResponseID) => {
const id3 = patchResponseID.id;
createAndRunRestAPIQuery(
"get_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"GET",
"",
[],
[],
true,
`/api/users/${id3}`
);
createAndRunRestAPIQuery(
"delete_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"DELETE",
"",
[],
[],
true,
`/api/users/${id3}`
);
createAndRunRestAPIQuery({
queryName: "put_restapi_id",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "PUT",
headersList: [["Content-Type", "application/json"]],
rawBody: '{"price": 500,"name": "Guitar"}',
urlSuffix: `/api/users/${id1}`,
expectedResponseShape: { price: 500, name: "Guitar", id: id1 },
});
createAndRunRestAPIQuery({
queryName: "patch_restapi_id",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "PATCH",
headersList: [["Content-Type", "application/json"]],
rawBody: '{"price": 999 }',
urlSuffix: `/api/users/${id1}`,
run: true,
expectedResponseShape: { price: 999, id: id1 },
});
createAndRunRestAPIQuery({
queryName: "get_restapi_id",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "GET",
urlSuffix: `/api/users/${id1}`,
run: true,
expectedResponseShape: { price: 999, name: "Guitar", id: id1 },
});
createAndRunRestAPIQuery({
queryName: "delete_restapi_id",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "DELETE",
urlSuffix: `/api/users/${id1}`,
run: true,
expectedResponseShape: { success: true },
});
}
);
cy.apiDeleteGDS(`cypress-${data.dataSourceName}-restapi`);
});
it("Should verify response for basic authentication type connection", () => {
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-restapi`,
"restapi",
[
{ key: "url", value: "https://httpbin.org" },
{ key: "auth_type", value: "basic" },
{ key: "grant_type", value: "authorization_code" },
{ key: "add_token_to", value: "header" },
{ key: "header_prefix", value: "Bearer " },
{ key: "access_token_url", value: "" },
{ key: "client_id", value: "" },
{
key: "client_secret",
encrypted: true,
credential_id: "b044a293-82b4-4381-84fd-d173c86a6a0c",
},
{ key: "audience", value: "" },
{ key: "scopes", value: "read, write" },
{ key: "username", value: "user", encrypted: false },
{ key: "password", value: "pass", encrypted: true },
{
key: "bearer_token",
encrypted: true,
credential_id: "21caf3cb-dbde-43c7-9f42-77feffb63062",
},
{ key: "auth_url", value: "" },
{ key: "client_auth", value: "header" },
{ key: "headers", value: [["", ""]] },
{ key: "custom_query_params", value: [["", ""]], encrypted: false },
{ key: "custom_auth_params", value: [["", ""]] },
{
key: "access_token_custom_headers",
value: [["", ""]],
encrypted: false,
},
{ key: "multiple_auth_enabled", value: false, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
{ key: "retry_network_errors", value: true, encrypted: false },
{ key: "url_parameters", value: [["", ""]], encrypted: false },
{ key: "tokenData", encrypted: false },
]
);
cy.reload();
cy.intercept("GET", "/api/library_apps").as("appLibrary");
cy.apiCreateApp(`${fake.companyName}-restAPI-Basic-App`);
createAndRunRestAPIQuery({
queryName: "get_basic_auth_valid",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "GET",
urlSuffix: "/basic-auth/user/pass",
expectedResponseShape: { authenticated: true, user: "user" },
});
createAndRunRestAPIQuery({
queryName: "get_basic_auth_invalid",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "GET",
urlSuffix: "/basic-auth/invaliduser/invalidpass",
});
cy.apiDeleteGDS(`cypress-${data.dataSourceName}-restapi`);
});
it("Should verify response for bearer authentication type connection", () => {
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-restapi`,
"restapi",
[
{ key: "url", value: "https://httpbin.org" },
{ key: "auth_type", value: "bearer" },
{ key: "grant_type", value: "authorization_code" },
{ key: "add_token_to", value: "header" },
{ key: "header_prefix", value: "Bearer " },
{ key: "access_token_url", value: "" },
{ key: "client_id", value: "" },
{
key: "client_secret",
encrypted: true,
credential_id: "b044a293-82b4-4381-84fd-d173c86a6a0c",
},
{ key: "audience", value: "" },
{ key: "scopes", value: "read, write" },
{ key: "username", value: "", encrypted: false },
{ key: "password", value: "", encrypted: true },
{
key: "bearer_token",
value: "my-token-123",
encrypted: true,
},
{ key: "auth_url", value: "" },
{ key: "client_auth", value: "header" },
{ key: "headers", value: [["", ""]] },
{ key: "custom_query_params", value: [["", ""]], encrypted: false },
{ key: "custom_auth_params", value: [["", ""]] },
{
key: "access_token_custom_headers",
value: [["", ""]],
encrypted: false,
},
{ key: "multiple_auth_enabled", value: false, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
{ key: "retry_network_errors", value: true, encrypted: false },
{ key: "url_parameters", value: [["", ""]], encrypted: false },
{ key: "tokenData", encrypted: false },
]
);
cy.reload();
cy.intercept("GET", "/api/library_apps").as("appLibrary");
cy.apiCreateApp(`${fake.companyName}-restAPI-Bearer-App`);
cy.openApp();
createAndRunRestAPIQuery({
queryName: "get_bearer_auth_valid",
dsName: `cypress-${data.dataSourceName}-restapi`,
method: "GET",
urlSuffix: "/bearer",
expectedResponseShape: { authenticated: true, token: "my-token-123" },
});
cy.intercept("GET", "api/data_sources?**").as("datasource");
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-restapi-invalid`,
"restapi",
[
{ key: "url", value: "https://httpbin.org" },
{ key: "auth_type", value: "bearer" },
{ key: "grant_type", value: "authorization_code" },
{ key: "add_token_to", value: "header" },
{ key: "header_prefix", value: "Bearer " },
{ key: "access_token_url", value: "" },
{ key: "client_id", value: "" },
{
key: "client_secret",
encrypted: true,
credential_id: "b044a293-82b4-4381-84fd-d173c86a6a0c",
},
{ key: "audience", value: "" },
{ key: "scopes", value: "read, write" },
{ key: "username", value: "", encrypted: false },
{ key: "password", value: "", encrypted: true },
{
key: "bearer_token",
value: "",
encrypted: true,
},
{ key: "auth_url", value: "" },
{ key: "client_auth", value: "header" },
{ key: "headers", value: [["", ""]] },
{ key: "custom_query_params", value: [["", ""]], encrypted: false },
{ key: "custom_auth_params", value: [["", ""]] },
{
key: "access_token_custom_headers",
value: [["", ""]],
encrypted: false,
},
{ key: "multiple_auth_enabled", value: false, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
{ key: "retry_network_errors", value: true, encrypted: false },
{ key: "url_parameters", value: [["", ""]], encrypted: false },
{ key: "tokenData", encrypted: false },
]
);
cy.apiCreateApp(`${fake.companyName}-restAPI-Bearer-invalid`);
cy.openApp();
createAndRunRestAPIQuery({
queryName: "get_bearer_auth_invalid",
dsName: `cypress-${data.dataSourceName}-restapi-invalid`,
method: "GET",
urlSuffix: "/bearer",
});
cy.apiDeleteGDS(`cypress-${data.dataSourceName}-restapi`);
});
it.skip("Should verify response for authentication code grant type connection", () => {
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-restapi`,
"restapi",
[
{
key: "url",
value: "https://dev-6lj2hoxdz5fg3m57.uk.auth0.com/api/v2/users",
},
{ key: "auth_type", value: "oauth2" },
{ key: "grant_type", value: "client_credentials" },
{ key: "add_token_to", value: "header" },
{ key: "header_prefix", value: "Bearer " },
{
key: "access_token_url",
value: "https://dev-6lj2hoxdz5fg3m57.uk.auth0.com/oauth/token",
},
{ key: "client_id", value: "JBDuuLU9vaSTP6Do7zYSkw0GvVgWhfyZ" },
{
key: "client_secret",
encrypted: true,
credential_id: "a6d26607-4d09-42a2-8bc0-e5c185c7c2f7",
},
{
key: "audience",
value: "https://dev-6lj2hoxdz5fg3m57.uk.auth0.com/api/v2/",
},
{ key: "scopes", value: "" },
{ key: "username", value: "", encrypted: false },
{
key: "password",
encrypted: true,
credential_id: "4502a906-b512-447a-a128-39f67e9778d2",
},
{
key: "bearer_token",
encrypted: true,
credential_id: "c94262c7-d2c5-4d7f-96f8-657689f2b1f0",
},
{ key: "auth_url", value: "" },
{ key: "client_auth", value: "header" },
{ key: "headers", value: [["", ""]] },
{ key: "custom_query_params", value: [["", ""]], encrypted: false },
{ key: "custom_auth_params", value: [["", ""]] },
{
key: "access_token_custom_headers",
value: [["", ""]],
encrypted: false,
},
{ key: "multiple_auth_enabled", value: false, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
{ key: "retry_network_errors", value: true, encrypted: false },
]
);
cy.reload();
cy.intercept("GET", "/api/library_apps").as("appLibrary");
cy.apiCreateApp(`${fake.companyName}-client-Grant-RestAPI`);
});
it("Should verify response for content-type", () => {
cy.apiCreateApp(`${fake.companyName}-restAPI-Content-App`);
createAndRunRestAPIQuery({
queryName: "post_json",
dsName: "restapidefault",
method: "POST",
url: "https://jsonplaceholder.typicode.com/posts",
headersList: [["Content-Type", "application/json"]],
rawBody: '{"title": "foo","body": "bar","userId": 1}',
run: true,
urlSuffix: "",
expectedResponseShape: { id: true, title: "foo", body: "bar", userId: 1 },
});
createAndRunRestAPIQuery({
queryName: "post_raw_text",
dsName: "restapidefault",
method: "POST",
url: "https://httpbin.org/post",
headersList: [["Content-Type", "text/plain"]],
rawBody: "This is plain text content",
jsonBody: null,
run: true,
expectedResponseShape: { data: "This is plain text content" },
});
createAndRunRestAPIQuery({
queryName: "post_form_urlencoded",
dsName: "restapidefault",
method: "POST",
url: "https://httpbin.org/post",
headersList: [["Content-Type", "application/x-www-form-urlencoded"]],
bodyList: [
["name", "Jane"],
["age", "30"],
],
expectedResponseShape: {
"form.name": "Jane",
"form.age": "30",
},
});
createAndRunRestAPIQuery({
queryName: "post_xml_soap",
dsName: "restapidefault",
method: "POST",
url: "http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL",
headersList: [["Content-Type", "text/xml; charset=utf-8"]],
rawBody: `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ListOfContinentsByName xmlns="http://www.oorsprong.org/websamples.countryinfo">
</ListOfContinentsByName>
</soap:Body>
</soap:Envelope>`,
jsonBody: null,
bodyList: [],
cookiesList: [["session", "abc123"]],
paramsList: [["lang", "en"]],
run: true,
shouldSucceed: true,
expectedResponseShape: {},
});
// createAndRunRestAPIQuery({
// queryName: "post_text_csv",
// dsName: "restapidefault",
// method: "POST",
// url: `https://tejasvi.free.beeceptor.com/csv-upload`,
// headersList: [["Content-Type", "text/csv"]],
// rawBody:
// "id,name,email\n1,Alice,alice@example.com\n2,Bob,bob@example.com",
// expectedResponseShape: {
// data: '{\n "status": "ok",\n "message": "File uploaded successfully",\n "body": id,name,email\n1,Alice,alice@example.com\n2,Bob,bob@example.com\n}',
// },
// });
// const filename = "tooljet.png";
// createAndRunRestAPIQuery({
// queryName: "upload_image",
// dsName: "restapidefault",
// method: "POST",
// url: `https://tejasvi.free.beeceptor.commultipart-upload`,
// headersList: [["Content-Type", "multipart/form-data"]],
// bodyList: [
// ["Image_File", "fixture:Image/tooljet.png"],
// ["filename", filename],
// ],
// expectedResponseShape: {
// filename: filename,
// },
// });
});
});

View file

@ -120,7 +120,7 @@ describe("Data sources AWS S3", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
s3Text.alertRegionIsMissing
);
@ -144,7 +144,7 @@ describe("Data sources AWS S3", () => {
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
s3Text.alertRegionIsMissing
);
@ -170,7 +170,7 @@ describe("Data sources AWS S3", () => {
.click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
s3Text.alertInvalidUrl
);
@ -188,7 +188,7 @@ describe("Data sources AWS S3", () => {
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
s3Text.accessKeyError
);
@ -207,7 +207,7 @@ describe("Data sources AWS S3", () => {
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
s3Text.sinatureError
);

View file

@ -105,7 +105,7 @@ describe("Data source SMTP", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
"Invalid credentials"
);

View file

@ -128,7 +128,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
"Invalid account. The specified value must be a valid subdomain string."
);

View file

@ -132,7 +132,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').verifyVisibleElement(
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
"Failed to connect to localhost:1433 - Could not connect (sequence)"
);

View file

@ -96,7 +96,7 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.buttonTextSave
);
cy.get('[data-cy="connection-alert-text"]').should(
cy.get(dataSourceSelector.connectionAlertText).should(
"have.text",
"Ensure that apiKey is set"
);

View file

@ -114,17 +114,30 @@ describe("App Version", () => {
cy.wait(3000);
// cy.reload();
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible", { timeout: 10000 });
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible", {
timeout: 10000,
});
// Preview and release verification
cy.openInCurrentTab(commonWidgetSelector.previewButton);
cy.url().should("include", "/home?version=v2");
cy.openApp("", Cypress.env("workspaceId"), Cypress.env("appId"), commonWidgetSelector.draggableWidget("text1"));
cy.openApp(
"",
Cypress.env("workspaceId"),
Cypress.env("appId"),
commonWidgetSelector.draggableWidget("text1")
);
releasedVersionAndVerify("v2");
});
it("should verify version management with components and queries", () => {
// Initial setup with component and datasource
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
data.datasourceName,
"restapi",
[{ key: "url", value: "https://jsonplaceholder.typicode.com/users" }]
);
cy.apiAddComponentToApp(
data.appName,
"text1",
@ -134,19 +147,15 @@ describe("App Version", () => {
);
cy.waitForAutoSave();
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
data.datasourceName,
"restapi",
[{ key: "url", value: "https://jsonplaceholder.typicode.com/users" }]
);
createRestAPIQuery(data.query1, data.datasourceName, "", "", "/1", true);
// Version v2 creation and verification
navigateToCreateNewVersionModal("v1");
createNewVersion(["v2"], "v1");
cy.get(commonWidgetSelector.draggableWidget("text1"))
.verifyVisibleElement("have.text", "Leanne Graham");
cy.get(commonWidgetSelector.draggableWidget("text1")).verifyVisibleElement(
"have.text",
"Leanne Graham"
);
cy.get(`[data-cy="list-query-${data.query1}"]`).should("be.visible");
// Modify v2 with new components and queries
@ -170,67 +179,79 @@ describe("App Version", () => {
create: { version: "v3", from: "v2" },
verify: {
component: { selector: "textInput", value: "Ervin Howell" },
query: data.query2
}
query: data.query2,
},
},
{
create: { version: "v4", from: "v1" },
verify: {
component: { selector: "text1", text: "Leanne Graham" },
query: data.query1
}
query: data.query1,
},
},
{
create: { version: "v5", from: "v3" },
verify: {
component: { selector: "textInput", value: "Ervin Howell" },
query: data.query2
}
}
query: data.query2,
},
},
];
versionChecks.forEach(check => {
versionChecks.forEach((check) => {
navigateToCreateNewVersionModal(check.create.from);
createNewVersion([check.create.version], check.create.from);
if (check.verify.component.value) {
cy.get(commonWidgetSelector.draggableWidget(check.verify.component.selector))
.verifyVisibleElement("have.value", check.verify.component.value);
cy.get(
commonWidgetSelector.draggableWidget(check.verify.component.selector)
).verifyVisibleElement("have.value", check.verify.component.value);
} else {
cy.get(commonWidgetSelector.draggableWidget(check.verify.component.selector))
.verifyVisibleElement("have.text", check.verify.component.text);
cy.get(
commonWidgetSelector.draggableWidget(check.verify.component.selector)
).verifyVisibleElement("have.text", check.verify.component.text);
}
cy.get(`[data-cy="list-query-${check.verify.query}"]`).should("be.visible");
cy.get(`[data-cy="list-query-${check.verify.query}"]`).should(
"be.visible"
);
});
// Release and version state verification
releasedVersionAndVerify("v5");
cy.get(appVersionSelectors.currentVersionField("v5"))
.should("have.class", "color-light-green");
cy.get(appVersionSelectors.currentVersionField("v5")).should(
"have.class",
"color-light-green"
);
// Version switching and component verification
cy.get(appVersionSelectors.currentVersionField("v5")).click();
cy.contains(`[id*="react-select-"]`, "v4").click();
cy.get(appVersionSelectors.currentVersionField("v4"))
.should("not.have.class", "color-light-green");
cy.get(commonWidgetSelector.draggableWidget("text1"))
.verifyVisibleElement("have.text", "Leanne Graham");
cy.get(appVersionSelectors.currentVersionField("v4")).should(
"not.have.class",
"color-light-green"
);
cy.get(commonWidgetSelector.draggableWidget("text1")).verifyVisibleElement(
"have.text",
"Leanne Graham"
);
cy.get(`[data-cy="list-query-${data.query1}"]`).should("be.visible");
// Preview and version switching verification
cy.openInCurrentTab(commonWidgetSelector.previewButton);
cy.url().should("include", "/home?version=v4");
cy.get(commonWidgetSelector.draggableWidget("text1"))
.verifyVisibleElement("have.text", "Leanne Graham");
cy.get(commonWidgetSelector.draggableWidget("text1")).verifyVisibleElement(
"have.text",
"Leanne Graham"
);
cy.get('[data-cy="preview-settings"]').click();
switchVersionAndVerify("v4", "v5");
cy.get(commonWidgetSelector.draggableWidget("textInput"))
.verifyVisibleElement("have.value", "Ervin Howell");
cy.get(
commonWidgetSelector.draggableWidget("textInput")
).verifyVisibleElement("have.value", "Ervin Howell");
//url validation should be added after bug fix
// cy.url().should("include", "/home?version=v5");
});
});

View file

@ -255,7 +255,7 @@ export const createRestAPIQuery = (
}).then((response) => {
const editingVersionId = response.body.editing_version.id;
const data_source_id = Cypress.env(kind);
const data_source_id = Cypress.env(`${dsName}`);
const requestBody = {
app_id: Cypress.env("appId"),

View file

@ -1,19 +1,31 @@
export const createAndRunRestAPIQuery = (
export const createAndRunRestAPIQuery = ({
queryName,
dsName,
method = "GET",
url = "",
urlSuffix = "",
headersList = [],
bodyList = [],
jsonBody = null,
rawBody = null,
cookiesList = [],
paramsList = [],
run = true,
urlSuffix = ""
) => {
expectedResponseShape = {},
authType = "",
authToken = "",
}) => {
cy.getCookie("tj_auth_token").then((cookie) => {
const headers = {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
};
// if (authType === "bearer" || authType === "oauth2") {
// headers["Authorization"] = `Bearer ${authToken}`;
// } else if (authType === "basic") {
// headers["Authorization"] = `Basic ${btoa(authToken)}`;
// }
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
@ -27,84 +39,108 @@ export const createAndRunRestAPIQuery = (
url: `${Cypress.env("server_host")}/api/data-sources/${Cypress.env("workspaceId")}/environments/${currentEnvironmentId}/versions/${editingVersionId}`,
headers,
}).then((dsResponse) => {
expect(dsResponse.status).to.eq(200);
const dataSource = dsResponse.body.data_sources.find(
(ds) => ds.name === dsName
);
if (!dataSource) {
throw new Error(`Data source '${dsName}' not found.`);
}
const data_source_id = dataSource.id;
const useJsonBody =
["POST", "PATCH", "PUT"].includes(method.toUpperCase()) &&
jsonBody !== null;
const useJson = jsonBody !== null;
const useRaw = rawBody !== null;
const useForm = bodyList?.length && !useJson && !useRaw;
const queryOptions = {
method: method.toLowerCase(),
url: url + urlSuffix,
url_params: [["", ""]],
url_params: paramsList.length ? paramsList : [["", ""]],
headers: headersList.length ? headersList : [["", ""]],
body: !useJsonBody && bodyList.length ? bodyList : [["", ""]],
json_body: useJsonBody ? jsonBody : null,
body_toggle: useJsonBody,
cookies: cookiesList.length ? cookiesList : [["", ""]],
body: useForm ? bodyList : [["", ""]],
json_body: useJson ? jsonBody : null,
raw_body: useRaw ? rawBody : "",
body_toggle: useJson || useRaw,
runOnPageLoad: run,
transformationLanguage: "javascript",
enableTransformation: false,
};
const requestBody = {
app_id: Cypress.env("appId"),
app_version_id: editingVersionId,
name: queryName,
kind: "restapi",
options: queryOptions,
data_source_id,
data_source_id: dataSource.id,
plugin_id: null,
};
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${data_source_id}/versions/${editingVersionId}`,
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${dataSource.id}/versions/${editingVersionId}`,
headers,
body: requestBody,
}).then((createResponse) => {
expect(createResponse.status).to.equal(201);
expect(createResponse.status).to.eq(201);
const queryId = createResponse.body.id;
cy.log("Query created successfully:", queryId);
const createdOptions = createResponse.body.options;
expect(createdOptions.method).to.equal(queryOptions.method);
expect(createdOptions.url).to.equal(queryOptions.url);
expect(createdOptions.headers).to.deep.equal(queryOptions.headers);
if (useJsonBody) {
expect(createdOptions.json_body).to.deep.equal(
queryOptions.json_body
);
expect(createdOptions.body_toggle).to.equal(true);
} else {
expect(createdOptions.body).to.deep.equal(queryOptions.body);
expect(createdOptions.body_toggle).to.equal(false);
}
expect(createdOptions.runOnPageLoad).to.equal(run);
cy.log("Metadata verified successfully");
if (run) {
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/data-queries/${queryId}/run`,
headers,
failOnStatusCode: false,
}).then((runResponse) => {
expect([200, 201]).to.include(runResponse.status);
cy.log("Query executed successfully:", runResponse.body);
if (runResponse.body?.data.id) {
cy.writeFile("cypress/fixtures/restAPI/storedId.json", {
id: runResponse.body.data.id,
});
cy.log("Stored ID:", runResponse.body.data.id);
const responseData = runResponse.body?.data;
const requestHeaders =
runResponse.body?.metadata?.request?.headers || {};
if (runResponse.body.status === "ok") {
expect([200, 201]).to.include(runResponse.status);
cy.log("Response:", responseData);
if (
expectedResponseShape &&
typeof expectedResponseShape === "object"
) {
Object.entries(expectedResponseShape).forEach(
([path, expected]) => {
const value = path
.split(".")
.reduce((obj, key) => obj?.[key], responseData);
if (expected === true) {
expect(value).to.not.be.undefined;
} else {
expect(value).to.eq(expected);
}
}
);
}
const expectedContentType = headersList.find(
([key]) => key.toLowerCase() === "content-type"
)?.[1];
if (expectedContentType && requestHeaders["content-type"]) {
expect(requestHeaders["content-type"]).to.include(
expectedContentType
);
}
if (Array.isArray(responseData)) {
responseData.forEach((item) => {
expect(item).to.have.any.keys("id", "name", "price");
});
}
if (responseData?.id) {
cy.writeFile("cypress/fixtures/restAPI/storedId.json", {
id: responseData.id,
});
}
} else if (runResponse.body.status === "failed") {
expect(runResponse.body.message).to.eq(
"Query could not be completed"
);
const statusCode =
runResponse.body?.metadata?.response?.statusCode;
expect([400, 401, 403, 404, 500]).to.include(statusCode);
cy.log(
"Failure validated as expected with status:",
statusCode
);
}
});
}