test: TED OAuth Automation (#21235)

## Description

- Automated TED OAuth 2.0 with authorization code

## How Has This Been Tested?
- Cypress test runs

## Checklist:
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test

---------

Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
This commit is contained in:
Vijetha-Kaja 2023-03-10 17:09:06 +05:30 committed by GitHub
parent 9b59ff469e
commit 1477d0d72a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 176 additions and 15 deletions

View File

@ -34,10 +34,19 @@
"redshift-databaseName": "fakeapi",
"redshift-username": "root",
"redshift-password": "Redshift$123",
"smtp-host":"host.docker.internal",
"smtp-port":"25",
"smtp-username":"root",
"smtp-password":"root",
"OAuth_Username":"testuser@appsmith.com",
"OAuth_Host":"http://localhost:6001",
"OAuth_ApiUrl": "http://host.docker.internal:6001",
"OAUth_AccessTokenUrl": "http://host.docker.internal:6001/oauth/token",
"OAuth_AuthUrl": "http://localhost:6001/oauth/authorize",
"OAuth_RedirectUrl":"http://localhost/api/v1/datasources/authorize",
"restapi-url": "https://my-json-server.typicode.com/typicode/demo/posts",
"connection-type": "Replica set",
"database-url": "appsmith-f9fe4.firebaseio.com",

View File

@ -2,18 +2,17 @@ const explorerLocators = require("../../../../locators/explorerlocators.json");
const guidedTourLocators = require("../../../../locators/GuidedTour.json");
const commonlocators = require("../../../../locators/commonlocators.json");
const homePage = require("../../../../locators/HomePage");
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
let datasources = ObjectsRegistry.DataSources;
import * as _ from "../../../../support/Objects/ObjectsCore";
describe("Creating new app after discontinuing guided tour should not start the same", function() {
it("1. Creating new app after discontinuing guided tour should not start the same", function() {
// Start guided tour
cy.get(commonlocators.homeIcon).click({ force: true });
datasources.CloseReconnectDataSourceModal(); // Check if reconnect data source modal is visible and close it
_.homePage.NavigateToHome();
_.dataSources.CloseReconnectDataSourceModal(); // Check if reconnect data source modal is visible and close it
cy.get(guidedTourLocators.welcomeTour)
.click()
.wait(2000);
datasources.CloseReconnectDataSourceModal(); // Check if reconnect data source modal is visible and close it
_.dataSources.CloseReconnectDataSourceModal(); // Check if reconnect data source modal is visible and close it
cy.get("body").then(($ele) => {
if ($ele.find(guidedTourLocators.welcomeTour).length) {
cy.get(guidedTourLocators.welcomeTour)
@ -21,7 +20,7 @@ describe("Creating new app after discontinuing guided tour should not start the
.wait(2000);
}
});
datasources.CloseReconnectDataSourceModal(); // Check if reconnect data source modal is visible and close it
_.dataSources.CloseReconnectDataSourceModal(); // Check if reconnect data source modal is visible and close it
cy.get("body").then(($ele) => {
if ($ele.find(guidedTourLocators.startBuilding).length == 0) {

View File

@ -0,0 +1,36 @@
import * as _ from "../../../../support/Objects/ObjectsCore";
//import * as _ from "@ObjectsCore"
describe("Authentiacted Api with OAuth 2.O authorization code test cases", function() {
it("1. Create & Save an Authenticated API with OAuth 2.O authorization code", function() {
// Create OAuth client
cy.fixture("datasources").then((datasourceFormData: any) => {
_.dataSources.CreateOAuthClient("authorization_code");
// Create datasource
_.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
cy.get("@OAuthClientID").then((clientId: any) => {
cy.get("@OAuthClientSecret").then((clientSecret: any) => {
_.dataSources.CreateOAuthDatasource(
"TED_OAuth_Api_" + uid,
"AuthCode",
clientId,
clientSecret,
);
//Create API from datasource
_.apiPage.CreateAndFillApi(
datasourceFormData["OAuth_ApiUrl"] + "/api/echo/get?ASDSA=ASDSA",
"EchoAPI_" + uid,
10000,
"GET",
true,
);
});
});
});
});
//Run API & Validate Response
_.apiPage.RunAPI();
_.apiPage.ResponseStatusCheck("200");
});
});

View File

@ -7,7 +7,7 @@ export class ApiPage {
public locator = ObjectsRegistry.CommonLocators;
private _createapi = ".t--createBlankApiCard";
private _resourceUrl = ".t--dataSourceField";
_resourceUrl = ".t--dataSourceField";
private _headerKey = (index: number) =>
".t--actionConfiguration\\.headers\\[0\\]\\.key\\." + index + "";
private _headerValue = (index: number) =>
@ -26,7 +26,7 @@ export class ApiPage {
".t--actionConfiguration\\.bodyFormData\\[0\\]\\.value\\." + index + "";
_bodyTypeDropdown =
"//span[text()='Type'][@class='bp3-button-text']/parent::button";
private _apiRunBtn = ".t--apiFormRunBtn";
_apiRunBtn = ".t--apiFormRunBtn";
private _queryTimeout =
"//input[@name='actionConfiguration.timeoutInMillisecond']";
_responseBody = ".CodeMirror-code span.cm-string.cm-property";
@ -57,13 +57,18 @@ export class ApiPage {
public _responseTabHeader = "[data-cy=t--tab-headers]";
public _autoGeneratedHeaderInfoIcon = (key: string) =>
`.t--auto-generated-${key}-info`;
private _createQuery = ".t--create-query";
CreateApi(
apiName = "",
apiVerb: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" = "GET",
aftDSSaved = false,
) {
cy.get(this.locator._createNew).click({ force: true });
cy.get(this._blankAPI).click({ force: true });
if (aftDSSaved) this.agHelper.GetNClick(this._createQuery);
else {
cy.get(this.locator._createNew).click({ force: true });
cy.get(this._blankAPI).click({ force: true });
}
this.agHelper.ValidateNetworkStatus("@createNewApi", 201);
// cy.get("@createNewApi").then((response: any) => {
@ -87,10 +92,10 @@ export class ApiPage {
apiName = "",
queryTimeout = 10000,
apiVerb: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" = "GET",
aftDSSaved = false,
) {
this.CreateApi(apiName, apiVerb);
this.CreateApi(apiName, apiVerb, aftDSSaved);
this.EnterURL(url);
this.agHelper.AssertAutoSave();
//this.agHelper.Sleep(2000);// Added because api name edit takes some time to reflect in api sidebar after the call passes.
cy.get(this._apiRunBtn).should("not.be.disabled");
if (queryTimeout != 10000) this.SetAPITimeout(queryTimeout);
@ -370,7 +375,7 @@ export class ApiPage {
ResponseStatusCheck(statusCode: string) {
this.agHelper.AssertElementVisible(this._responseStatus);
this.agHelper.GetNAssertContains(this._responseStatus, statusCode)
this.agHelper.GetNAssertContains(this._responseStatus, statusCode);
}
public SelectPaginationTypeViaIndex(index: number) {
cy.get(this._paginationTypeLabels)

View File

@ -123,17 +123,22 @@ export class DataSources {
public _urlInputControl = "input[name='url']";
// Authenticated API locators
private _authApiDatasource = ".t--createAuthApiDatasource";
private _authType = "[data-cy=authType]";
private _oauth2 = ".t--dropdown-option:contains('OAuth 2.0')";
private _accessTokenUrl = "[data-cy='authentication.accessTokenUrl'] input";
private _scope = "[data-cy='authentication.scopeString'] input";
private _clientID = "[data-cy='authentication.clientId'] input";
private _clientSecret = "[data-cy='authentication.clientSecret'] input";
private _clientCredentails =
".t--dropdown-option:contains('Client Credentials')";
private _authorizationCode =
".t--dropdown-option:contains('Authorization Code')";
private _grantType = "[data-cy='authentication.grantType']";
private _authorizationURL =
"[data-cy='authentication.authorizationUrl'] input";
private _consent = '[name="confirm"]';
private _consentSubmit = "//button[text()='Submit']";
public _datasourceModalSave = ".t--datasource-modal-save";
public _datasourceModalDoNotSave = ".t--datasource-modal-do-not-save";
public _deleteDatasourceButton = ".t--delete-datasource";
@ -481,7 +486,7 @@ export class DataSources {
}
public NavigateToActiveTab() {
this.agHelper.GetElement(this.locator._body).then(($body) => {
this.agHelper.GetElement(this.locator._body).then(($body) => {
if ($body.find(this._selectedActiveTab).length == 0) {
this.NavigateToDSCreateNew();
this.agHelper.GetNClick(this._activeTab, 0, true);
@ -900,4 +905,111 @@ export class DataSources {
uri,
);
}
public CreateOAuthClient(grantType: string) {
let clientId, clientSecret;
// Login to TED OAuth
let formData = new FormData();
formData.append("username", datasourceFormData["OAuth_Username"]);
cy.request("POST", datasourceFormData["OAuth_Host"], formData).then(
(response) => {
expect(response.status).to.equal(200);
},
);
// Create client
let clientData = new FormData();
clientData.append("client_name", "appsmith_cs_post");
clientData.append("client_uri", "http://localhost/");
clientData.append("scope", "profile");
clientData.append("redirect_uri", datasourceFormData["OAuth_RedirectUrl"]);
clientData.append("grant_type", grantType);
clientData.append("response_type", "code");
clientData.append("token_endpoint_auth_method", "client_secret_post");
cy.request(
"POST",
datasourceFormData["OAuth_Host"] + "/create_client",
clientData,
).then((response) => {
expect(response.status).to.equal(200);
});
// Get Client Credentials
cy.request("GET", datasourceFormData["OAuth_Host"]).then((response) => {
clientId = response.body.split("client_id: </strong>");
clientId = clientId[1].split("<strong>client_secret: </strong>");
clientSecret = clientId[1].split("<strong>");
clientSecret = clientSecret[0].trim();
clientId = clientId[0].trim();
cy.wrap(clientId).as("OAuthClientID");
cy.wrap(clientSecret).as("OAuthClientSecret");
});
}
public CreateOAuthDatasource(
datasourceName: string,
grantType: "ClientCredentials" | "AuthCode",
clientId: string,
clientSecret: string,
) {
this.NavigateToDSCreateNew();
//Click on Authenticated API
cy.get(this._authApiDatasource).click({ force: true });
this.FillAPIOAuthForm(datasourceName, grantType, clientId, clientSecret);
// save datasource
this.agHelper.Sleep(500);
this.agHelper.GetNClick(this._saveAndAuthorizeDS);
//Accept consent
this.agHelper.GetNClick(this._consent);
this.agHelper.GetNClick(this._consentSubmit);
//Validate save
this.agHelper.ValidateNetworkStatus("@saveDatasource", 201);
}
public FillAPIOAuthForm(
dsName: string,
grantType: "ClientCredentials" | "AuthCode",
clientId: string,
clientSecret: string,
) {
this.agHelper.RenameWithInPane(dsName, false);
// Fill Auth Form
this.agHelper.UpdateInput(
this.locator._inputFieldByName("URL"),
datasourceFormData["OAuth_ApiUrl"],
);
this.agHelper.GetNClick(this._authType);
this.agHelper.GetNClick(this._oauth2);
this.agHelper.GetNClick(this._grantType);
if (grantType == "ClientCredentials")
this.agHelper.GetNClick(this._clientCredentails);
else if (grantType == "AuthCode")
this.agHelper.GetNClick(this._authorizationCode);
this.agHelper.UpdateInput(
this.locator._inputFieldByName("Access Token URL"),
datasourceFormData["OAUth_AccessTokenUrl"],
);
this.agHelper.UpdateInput(
this.locator._inputFieldByName("Client ID"),
clientId,
);
this.agHelper.UpdateInput(
this.locator._inputFieldByName("Client Secret"),
clientSecret,
);
this.agHelper.UpdateInput(
this.locator._inputFieldByName("Scope(s)"),
"profile",
);
this.agHelper.UpdateInput(
this.locator._inputFieldByName("Authorization URL"),
datasourceFormData["OAuth_AuthUrl"],
);
}
}