test: Cypress | Moving Non-TED containers within Tests (#24709)

## Description
- This PR improves the container start for 
- Arango DB - Container started moved to test case level
- MsSql - Delete container added
- Elastic - Container started moved to test case level
- Starts container, runs tests, stops containers & deletes it too 🤞🏻
- Removed containers start from yml file
- Flaky fixes below:
         - Apps/ReconnectDatasource_spec.js
         - Improved FillPostgresDSForm()

#### Type of change
- Script fix (non-breaking change which fixes an issue)

## Testing
#### How Has This Been Tested?
- [X] Cypress CI runs

## Checklist:
#### QA activity:
- [X] Added `Test Plan Approved` label after all changes are reviewed
This commit is contained in:
Aishwarya-U-R 2023-06-21 23:07:21 +05:30 committed by GitHub
parent 11a18d1d08
commit 91325d258e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 605 additions and 121 deletions

View File

@ -157,18 +157,6 @@ jobs:
--add-host=host.docker.internal:host-gateway --add-host=api.segment.io:host-gateway --add-host=t.appsmith.com:host-gateway \
cicontainer
- name: Setup Arango docker & ElasticSearch containers
working-directory: app/client/cypress
run: |
docker run --name arangodb -e ARANGO_USERNAME=root -e ARANGO_ROOT_PASSWORD=Arango -p 8529:8529 -d arangodb
docker run --name elasticsearch -d -p 9200:9200 -e "discovery.type=single-node" -e "ELASTIC_USERNAME=elastic" -e "ELASTIC_PASSWORD=docker" -e "xpack.security.enabled=true" docker.elastic.co/elasticsearch/elasticsearch:7.16.2
# docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf"
# docker restart mssqldb
# sudo ufw allow 1433/tcp
# docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql
# docker run --name=mssqldb -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Root@123" -p 1433:1433 -d mcr.microsoft.com/azure-sql-edge
- name: Use Node.js 16.14.0
uses: actions/setup-node@v3
with:

View File

@ -154,18 +154,6 @@ jobs:
--add-host=host.docker.internal:host-gateway --add-host=api.segment.io:host-gateway --add-host=t.appsmith.com:host-gateway \
cicontainer
- name: Setup Arango docker & ElasticSearch containers
working-directory: app/client/cypress
run: |
docker run --name arangodb -e ARANGO_USERNAME=root -e ARANGO_ROOT_PASSWORD=Arango -p 8529:8529 -d arangodb
docker run --name elasticsearch -d -p 9200:9200 -e "discovery.type=single-node" -e "ELASTIC_USERNAME=elastic" -e "ELASTIC_PASSWORD=docker" -e "xpack.security.enabled=true" docker.elastic.co/elasticsearch/elasticsearch:7.16.2
# docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf"
# docker restart mssqldb
# sudo ufw allow 1433/tcp
# docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql
# docker run --name=mssqldb -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Root@123" -p 1433:1433 -d mcr.microsoft.com/azure-sql-edge
- name: Use Node.js 16.14.0
if: steps.run_result.outputs.run_result != 'success'
uses: actions/setup-node@v3

View File

@ -1,7 +1,4 @@
const commonlocators = require("../../../../../locators/commonlocators.json");
const viewWidgetsPage = require("../../../../../locators/ViewWidgets.json");
const publish = require("../../../../../locators/publishWidgetspage.json");
const modalWidgetPage = require("../../../../../locators/ModalWidget.json");
const widgetsPage = require("../../../../../locators/Widgets.json");
import * as _ from "../../../../../support/Objects/ObjectsCore";

View File

@ -1,13 +1,17 @@
import {
agHelper,
entityExplorer,
dataSources,
entityItems,
entityExplorer,
} from "../../../../support/Objects/ObjectsCore";
let dsName: any, books: any;
describe("Validate Elasticsearch DS", () => {
let dsName: any,
books: any,
containerName = "elasticsearch1";
before("Create a new ElasticSearch DS", () => {
dataSources.StartContainerNVerify("Elasticsearch", containerName);
dataSources.CreateDataSource("Elasticsearch");
cy.get("@dsName").then(($dsName) => {
dsName = $dsName;
@ -201,5 +205,6 @@ describe("Validate Elasticsearch DS", () => {
action: "Delete",
entityType: entityItems.Datasource,
});
dataSources.StopNDeleteContainer(containerName);
});
});

View File

@ -5,30 +5,12 @@ import {
dataSources,
} from "../../../support/Objects/ObjectsCore";
let dsName: any,
collectionName = "countries_places_to_visit";
const tedUrl = "http://localhost:5001/v1/parent/cmd";
describe("Validate Arango & CURL Import Datasources", () => {
let dsName: any,
collectionName = "countries_places_to_visit",
containerName = "arangodb";
before("Create a new Arango DS", () => {
// let ArangoDB =
// "mkdir -p `$PWD`/arangodb/bin/bash;
// docker run --name arangodb -e ARANGO_USERNAME=root -e ARANGO_ROOT_PASSWORD=Arango -p 8529:8529 -v ~/arango/bin/bash:/arango/bin/bash -d arangodb";
// cy.request({
// method: "GET",
// url: tedUrl,
// qs: {
// cmd: ArangoDB,
// },
// }).then((res) => {
// cy.log("ContainerID", res.body.stdout);
// cy.log(res.body.stderr);
// expect(res.status).equal(200);
// });
// //Wait for the container to be up
// agHelper.Sleep(10000);
dataSources.StartContainerNVerify("Arango", containerName, 20000);
dataSources.CreateDataSource("Arango");
cy.get("@dsName").then(($dsName) => {
dsName = $dsName;
@ -356,5 +338,7 @@ describe("Validate Arango & CURL Import Datasources", () => {
//Deleting datasource finally
dataSources.DeleteDatasouceFromWinthinDS(dsName);
});
dataSources.StopNDeleteContainer(containerName);
});
});

View File

@ -7,19 +7,13 @@ import {
} from "../../../support/Objects/ObjectsCore";
import { Widgets } from "../../../support/Pages/DataSources";
let dsName: any, query: string;
describe("Validate MsSQL connection & basic querying with UI flows", () => {
let dsName: any,
query: string,
containerName = "mssqldb";
before("Create MsSql container & adding data into it", () => {
cy.exec(
'docker run --name=mssqldb -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Root@123" -p 1433:1433 -d mcr.microsoft.com/azure-sql-edge',
).then((result) => {
// Handle the command execution result
// The MSSQL container should be running at this point
cy.log("Run id of started container is:" + result.stdout);
cy.log("Error from MsSQL container start action:" + result.stderr);
agHelper.Sleep(10000); //allow some time for container to start
});
dataSources.StartContainerNVerify("MsSql", containerName, 20000);
dataSources.CreateDataSource("MsSql");
cy.get("@dsName").then(($dsName) => {
@ -141,6 +135,7 @@ describe("Validate MsSQL connection & basic querying with UI flows", () => {
action: "Delete",
entityType: entityItems.Datasource,
});
dataSources.StopNDeleteContainer(containerName);
});
function runQueryNValidate(query: string, columnHeaders: string[]) {

View File

@ -1,7 +1,6 @@
import homePage from "../../../locators/HomePage";
import reconnectDatasourceModal from "../../../locators/ReconnectLocators";
const datasource = require("../../../locators/DatasourcesEditor.json");
import homePageLocators from "../../../locators/HomePage";
import * as _ from "../../../support/Objects/ObjectsCore";
import { homePage, dataSources } from "../../../support/Objects/ObjectsCore";
describe("Reconnect Datasource Modal validation while importing application", function () {
let workspaceId;
@ -9,7 +8,7 @@ describe("Reconnect Datasource Modal validation while importing application", fu
let newWorkspaceName;
let appName;
it("1. Import application from json with one postgres and success modal", function () {
_.homePage.NavigateToHome();
homePage.NavigateToHome();
// import application
cy.generateUUID().then((uid) => {
workspaceId = uid;
@ -17,10 +16,12 @@ describe("Reconnect Datasource Modal validation while importing application", fu
cy.createWorkspace();
cy.wait("@createWorkspace").then((createWorkspaceInterception) => {
newWorkspaceName = createWorkspaceInterception.response.body.data.name;
_.homePage.RenameWorkspace(newWorkspaceName, workspaceId);
cy.get(homePage.workspaceImportAppOption).click({ force: true });
cy.get(homePage.workspaceImportAppModal).should("be.visible");
cy.xpath(homePage.uploadLogo)
homePage.RenameWorkspace(newWorkspaceName, workspaceId);
cy.get(homePageLocators.workspaceImportAppOption).click({
force: true,
});
cy.get(homePageLocators.workspaceImportAppModal).should("be.visible");
cy.xpath(homePageLocators.uploadLogo)
.first()
.selectFile("cypress/fixtures/one_postgres.json", {
force: true,
@ -30,52 +31,16 @@ describe("Reconnect Datasource Modal validation while importing application", fu
// should check reconnect modal openning
const { isPartialImport } = interception.response.body.data;
if (isPartialImport) {
// should reconnect modal
cy.get(reconnectDatasourceModal.Modal).should("be.visible");
cy.get(".t--ds-list .t--ds-list-title", {
withinSubject: null,
}).should("be.visible");
cy.get(".t--ds-list .t--ds-list-title").should(
"have.text",
dataSources.ReconnectDataSource(
"Untitled Datasource",
"PostgreSQL",
);
// not configured yet
cy.get(".t--ds-list .ads-v2-icon").should("be.visible");
// check db type
cy.get(".t--ds-list").contains("PostgreSQL");
// check the postgres form config with default value
cy.get("[data-testid='section-Connection']").should("be.visible");
cy.get(datasource.authenticationSettingsSection).should(
"be.visible",
);
cy.get(datasource.sslSettingsSection).should("be.visible");
cy.get(
"[data-testid='datasourceConfiguration.connection.mode']",
).should("contain", "Read / Write");
cy.get(datasource.sslSettingsSection).click({ force: true });
// should expand ssl pan
cy.get(
"[data-testid='datasourceConfiguration.connection.ssl.authType']",
).should("contain", "Default");
cy.ReconnectDatasource("Untitled Datasource");
cy.wait(1000);
cy.fillPostgresDatasourceForm();
cy.testDatasource(true);
cy.get(".t--save-datasource").click({ force: true });
cy.wait(2000);
// cy.get(reconnectDatasourceModal.SkipToAppBtn).click({
// force: true,
// });
// cy.wait(2000);
} else {
cy.get(homePage.toastMessage).should(
cy.get(homePageLocators.toastMessage).should(
"contain",
"Application imported successfully",
);
}
cy.wait("@getWorkspace");
// check datasource configured success modal
cy.get(".t--import-app-success-modal").should("be.visible");
cy.get(".t--import-app-success-modal").should(
@ -89,12 +54,12 @@ describe("Reconnect Datasource Modal validation while importing application", fu
const uuid = () => Cypress._.random(0, 1e4);
const name = uuid();
appName = `app${name}`;
cy.get(homePage.applicationName).click({ force: true });
cy.get(homePageLocators.applicationName).click({ force: true });
cy.get(".ads-v2-menu__menu-item-children:contains(Edit)")
.eq(0)
.click();
cy.wait(2000);
cy.get(homePage.applicationName)
cy.get(homePageLocators.applicationName)
// .clear()
.type(appName);
});

File diff suppressed because one or more lines are too long

View File

@ -23,17 +23,33 @@ export class DefaultHostPort {
mssql_databaseName = "fakeapi";
mssql_username = "SA";
mssql_password = "Root@123";
mssql_docker = (containerName: string) =>
`docker run --name=${containerName} -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=${
this.mssql_password
}" -p ${this.mssql_port.toString()}:${this.mssql_port.toString()} -d mcr.microsoft.com/azure-sql-edge`;
arango_host = "host.docker.internal";
arango_port = 8529;
arango_databaseName = "_system";
arango_username = "root";
arango_password = "Arango";
arango_docker = (containerName: string) =>
`docker run --name ${containerName} -e ARANGO_USERNAME=${
this.arango_username
} -e ARANGO_ROOT_PASSWORD=${
this.arango_password
} -p ${this.arango_port.toString()}:${this.arango_port.toString()} -d arangodb`;
elastic_host = "http://host.docker.internal";
elastic_port = 9200;
elastic_username = "elastic";
elastic_password = "docker";
elastic_docker = (containerName: string) =>
`docker run --name ${containerName} -d -p ${this.elastic_port.toString()}:${this.elastic_port.toString()} -e "discovery.type=single-node" -e "ELASTIC_USERNAME=${
this.elastic_username
}" -e "ELASTIC_PASSWORD=${
this.elastic_password
}" -e "xpack.security.enabled=true" docker.elastic.co/elasticsearch/elasticsearch:7.16.2`;
redshift_host = "localhost";
redshift_port = 543;

View File

@ -819,10 +819,7 @@ export class AggregateHelper extends ReusableHelper {
}
public GetElementLength(selector: string) {
const locator = selector.startsWith("//")
? cy.xpath(selector)
: cy.get(selector);
return locator.its("length");
return this.GetElement(selector).its("length");
}
public Sleep(timeout = 1000) {

View File

@ -37,6 +37,14 @@ export class DataSources {
private hp = ObjectsRegistry.DefaultHostPort;
private assertHelper = ObjectsRegistry.AssertHelper;
public ContainerKVP = (containerName: string) => {
return {
MsSql: this.hp.mssql_docker(containerName),
Arango: this.hp.arango_docker(containerName),
Elasticsearch: this.hp.elastic_docker(containerName),
};
}; //Container KeyValuePair
private _dsCreateNewTab = "[data-testid=t--tab-CREATE_NEW]";
private _addNewDataSource = ".t--entity-add-btn.datasources button";
private _createNewPlgin = (pluginName: string) =>
@ -221,6 +229,8 @@ export class DataSources {
"[data-testid='t--where-clause-delete-[" + index + "]']";
_bodyCodeMirror = "//div[contains(@class, 't--actionConfiguration.body')]";
private _reconnectModalDSToolTip = ".t--ds-list .t--ds-list-title";
private _reconnectModalDSToopTipIcon = ".t--ds-list .ads-v2-icon";
public AssertDSEditViewMode(mode: "Edit" | "View") {
if (mode == "Edit") this.agHelper.AssertElementAbsence(this._editButton);
@ -437,6 +447,8 @@ export class DataSources {
cy.get(this._password).type(
password == "" ? this.hp.postgres_username : password,
);
this.ExpandSectionByName("SSL (optional)");
this.ValidateNSelectDropdown("SSL mode", "Default");
}
public FillOracleDSForm(
@ -567,7 +579,6 @@ export class DataSources {
public FillElasticSearchDSForm() {
this.agHelper.UpdateInputValue(this._host, this.hp.elastic_host);
this.agHelper.UpdateInputValue(this._port, this.hp.elastic_port.toString());
this.ExpandSectionByName("Authentication");
this.agHelper.UpdateInputValue(this._username, this.hp.elastic_username);
@ -830,12 +841,23 @@ export class DataSources {
public ReconnectDataSource(dbName: string, dsName: "PostgreSQL" | "MySQL") {
this.agHelper.AssertElementVisible(this._reconnectModal);
this.agHelper.AssertElementVisible(this._testDs); //Making sure modal is fully loaded
cy.xpath(this._activeDSListReconnectModal(dsName)).should("be.visible");
cy.xpath(this._activeDSListReconnectModal(dbName)).should("be.visible"); //.click()
this.agHelper.AssertElementVisible(
this._activeDSListReconnectModal(dsName),
);
this.agHelper.AssertElementVisible(
this._activeDSListReconnectModal(dbName),
);
//Checking if tooltip for Ds name & icon is present (useful in cases of long name for ds)
this.agHelper.AssertText(this._reconnectModalDSToolTip, "text", dbName);
this.agHelper.AssertElementVisible(this._reconnectModalDSToopTipIcon);
this.ValidateNSelectDropdown("Connection mode", "Read / Write");
if (dsName == "PostgreSQL") this.FillPostgresDSForm();
else if (dsName == "MySQL") this.FillMySqlDSForm();
cy.get(this._saveDs).click();
this.agHelper.GetNClick(this._saveDs);
this.assertHelper.AssertNetworkStatus("@getPage", 200);
this.assertHelper.AssertNetworkStatus("getWorkspace");
}
RunQuery({
@ -1342,4 +1364,64 @@ export class DataSources {
inputFieldName: fieldLabel,
});
}
public StopNDeleteContainer(containerName: string) {
// Stop the container
cy.exec(`docker stop ${containerName}`).then((stopResult) => {
cy.log("Output from stopping container:" + stopResult.stdout);
cy.log("Error from stopping container:" + stopResult.stderr);
// Delete the container
cy.exec(`docker rm ${containerName}`).then((deleteResult) => {
cy.log("Output from deleting container:" + deleteResult.stdout);
cy.log("Error from deleting container:" + deleteResult.stderr);
});
});
}
public IsContainerReady(containerName: string) {
return cy
.exec(`docker inspect -f '{{.State.Status}}' ${containerName}`)
.then((result) => {
const containerStatus = result.stdout.trim();
return containerStatus === "running";
});
}
public StartContainerNVerify(
containerType: "MsSql" | "Arango" | "Elasticsearch",
containerName: string,
timeout = 30000,
) {
let containerCommand = "";
switch (containerType) {
case "MsSql":
containerCommand = this.ContainerKVP(containerName).MsSql;
break;
case "Arango":
containerCommand = this.ContainerKVP(containerName).Arango;
break;
case "Elasticsearch":
containerCommand = this.ContainerKVP(containerName).Elasticsearch;
break;
default:
break;
}
cy.exec(containerCommand).then((result) => {
// Wait for the container to be ready
cy.waitUntil(() => this.IsContainerReady(containerName), {
interval: 5000,
timeout: 60000,
}).then((isReady) => {
if (isReady) {
cy.log("Run id of started container is:" + result.stdout);
this.agHelper.Sleep(timeout); //allow some time for container to settle start for CI
} else
cy.log(
`Error from ${containerName} container start action:` +
result.stderr,
); // Container did not start properly within the timeout
});
});
}
}

View File

@ -269,7 +269,7 @@ Cypress.Commands.add("CreateAppInFirstListedWorkspace", (appname) => {
cy.wait(4000);
cy.get("#loading").should("not.exist");
cy.get("#sidebar").should("be.visible");
cy.wait("@updateLayout")
cy.wait("@getPluginForm") //replacing this since flaky in CI - to monitor
.its("response.body.responseMeta.status")
.should("eq", 200);