PromucFlow_constructor/app/client/cypress/support/Pages/GitSync.ts
Trisha Anand 783bd104ca
chore: Adding missing function in cypress git sync helper and syncing the common file across the two repositories. (#33368)
Fixes GitSync spec in CE repo. 

Previous PR which got dirty due to prettier check :
https://github.com/appsmithorg/appsmith/pull/33360

## Description
> [!TIP]  
> _Add a TL;DR when the description is longer than 500 words or
extremely technical (helps the content, marketing, and DevRel team)._
>
> _Please also include relevant motivation and context. List any
dependencies that are required for this change. Add links to Notion,
Figma or any other documents that might be relevant to the PR._


Fixes #`Issue Number`  
_or_  
Fixes `Issue URL`
> [!WARNING]  
> _If no issue exists, please create an issue first, and check with the
maintainers if the issue is valid._

## Automation

/ok-to-test tags=""

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!CAUTION]  
> If you modify the content in this section, you are likely to disrupt
the CI result for your PR.

<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No
2024-05-13 10:19:49 +05:30

468 lines
16 KiB
TypeScript

import { ObjectsRegistry } from "../Objects/Registry";
const GITHUB_API_BASE = "https://api.github.com";
//const GITEA_API_BASE = "http://35.154.225.218";
import {
createMessage,
UNABLE_TO_IMPORT_APP,
} from "../../../src/ce/constants/messages";
export class GitSync {
public agHelper = ObjectsRegistry.AggregateHelper;
public locator = ObjectsRegistry.CommonLocators;
private dataManager = ObjectsRegistry.DataManager;
private assertHelper = ObjectsRegistry.AssertHelper;
private homePage = ObjectsRegistry.HomePage;
private _connectGitBottomBar = ".t--connect-git-bottom-bar";
public _gitSyncModal = "[data-testid=t--git-sync-modal]";
private _closeGitSyncModal =
"//div[@data-testid='t--git-sync-modal']//button[@aria-label='Close']";
private _closeGitSettingsModal =
"//div[@data-testid='t--git-settings-modal']//button[@aria-label='Close']";
//private _closeGitSyncModal = ".ads-v2-modal__content-header-close-button";
private _gitRepoInput =
"//label[text()='Remote URL']/following-sibling::div//input";
private _useDefaultConfig = "//label[text()='Use default configuration']";
private _gitConfigNameInput =
"//label[text()='Author name']/following-sibling::div//input";
private _gitConfigEmailInput =
"//label[text()='Author email']/following-sibling::div//input";
_branchButton = ".t--branch-button";
private _branchSearchInput = ".t--branch-search-input input";
public _bottomBarCommit = ".t--bottom-bar-commit button";
public _gitPullCount = ".t--bottom-bar-commit .count";
_bottomBarPull = ".t--bottom-bar-pull button";
private _branchName = (branch: string) =>
"//button[contains(@class, 't--branch-button')]//*[text()='" +
branch +
"']";
_checkMergeability = "//span[contains(text(), 'Checking mergeability')]";
public _branchListItem = "[data-testid=t--branch-list-item]";
public _bottomBarMergeButton = ".t--bottom-bar-merge";
private mergeCTA = "[data-testid=t--git-merge-button]";
public _mergeBranchDropdownDestination =
".t--merge-branch-dropdown-destination";
public _dropdownmenu = ".rc-select-item-option-content";
private _openRepoButton = "[data-testid=t--git-repo-button]";
public _commitButton = ".t--commit-button";
public _commitCommentInput = ".t--commit-comment-input textarea";
public _discardChanges = ".t--discard-button";
public _discardCallout = "[data-testid='t--discard-callout']";
public _gitStatusChanges = "[data-testid='t--git-status-changes']";
private _gitSyncBranches = ".t--sync-branches";
learnMoreSshUrl = ".t--learn-more-ssh-url";
repoLimitExceededErrorModal = ".t--git-repo-limited-modal";
public _bottomSettingsBtn = ".t--bottom-git-settings";
public _defaultBranchSelect = "[data-testid='t--git-default-branch-select']";
public _defaultBranchUpdateBtn =
"[data-testid='t--git-default-branch-update-btn']";
public _protectedBranchesSelect =
"[data-testid='t--git-protected-branches-select']";
public _protectedBranchesUpdateBtn =
"[data-testid='t--git-protected-branches-update-btn']";
public _gitSettingsModal = "[data-testid='t--git-settings-modal']";
public _settingsTabGeneral = "[data-testid='t--tab-GENERAL']";
public _settingsTabBranch = "[data-testid='t--tab-BRANCH']";
public _branchProtectionSelectDropdown =
"[data-testid='t--git-protected-branches-select']";
public _branchProtectionUpdateBtn =
"[data-testid='t--git-protected-branches-update-btn']";
public _disconnectGitBtn = "[data-testid='t--git-disconnect-btn']";
public _mergeLoader = "[data-testid='t--git-merge-loader']";
OpenGitSyncModal() {
this.agHelper.GetNClick(this._connectGitBottomBar);
this.agHelper.AssertElementVisibility(this._gitSyncModal);
}
CloseGitSyncModal() {
this.agHelper.GetNClick(this._closeGitSyncModal);
this.agHelper.AssertElementAbsence(this._gitSyncModal);
}
OpenGitSettingsModal(tabName: "GENERAL" | "BRANCH" | "CD" = "GENERAL") {
this.agHelper.GetNClick(this._bottomSettingsBtn);
this.agHelper.AssertElementVisibility(this._gitSettingsModal);
if (tabName !== "GENERAL") {
this.agHelper.GetNClick(`[data-testid='t--tab-${tabName}']`);
}
}
CloseGitSettingsModal() {
this.agHelper.GetNClick(this._closeGitSettingsModal);
this.agHelper.AssertElementAbsence(this._gitSettingsModal);
}
GetCurrentBranchName() {
return this.agHelper.GetText(this._branchButton, "text", 0);
}
public CreateTestGiteaRepo(repo: string, privateFlag = false) {
cy.request({
method: "POST",
url: `${this.dataManager.GIT_API_BASE}/api/v1/git/repos`,
body: {
name: repo,
private: privateFlag,
},
});
}
private providerRadioOthers = "[data-testid='t--git-provider-radio-others']";
private existingEmptyRepoYes = "[data-testid='t--existing-empty-repo-yes']";
private gitConnectNextBtn = "[data-testid='t--git-connect-next-button']";
private remoteUrlInput = "[data-testid='git-connect-remote-url-input']";
private addedDeployKeyCheckbox =
"[data-testid='t--added-deploy-key-checkbox']";
private startUsingGitButton =
"[data-testid='t--git-success-modal-start-using-git-cta']";
private existingRepoCheckbox = "[data-testid='t--existing-repo-checkbox']";
CreateNConnectToGit(
repoName = "Repo",
assertConnect = true,
privateFlag = false,
removeDefaultBranchProtection = true,
) {
this.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
repoName += uid;
this.CreateTestGiteaRepo(repoName, privateFlag);
cy.intercept("POST", "/api/v1/applications/ssh-keypair/*").as(
`generateKey-${repoName}`,
);
cy.intercept("GET", "/api/v1/git/branch/app/*/protected").as(
`protected-${repoName}`,
);
cy.intercept("GET", "/api/v1/git/branch/app/*").as(
`branches-${repoName}`,
);
this.OpenGitSyncModal();
this.agHelper.GetNClick(this.providerRadioOthers);
this.agHelper.GetNClick(this.existingEmptyRepoYes);
this.agHelper.GetNClick(this.gitConnectNextBtn);
this.agHelper.AssertAttribute(
this.remoteUrlInput,
"placeholder",
"git@example.com:user/repository.git",
);
this.agHelper.TypeText(
this.remoteUrlInput,
`${this.dataManager.GIT_CLONE_URL}/${repoName}.git`,
);
this.agHelper.GetNClick(this.gitConnectNextBtn);
this.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
cy.wait(`@generateKey-${repoName}`).then((result: any) => {
let generatedKey = result.response.body.data.publicKey;
// fetch the generated key and post to the github repo
cy.request({
method: "POST",
url: `${this.dataManager.GIT_API_BASE}/api/v1/git/keys/${repoName}`,
body: {
title: "key_" + uid,
key: generatedKey,
read_only: false,
},
}).then((resp: any) => {
cy.log("Deploy Key Id ", resp.body.key_id);
cy.wrap(resp.body.key_id).as("deployKeyId");
});
});
});
this.agHelper.GetNClick(this.addedDeployKeyCheckbox, 0, true);
this.agHelper.GetNClick(this.gitConnectNextBtn);
if (assertConnect) {
this.assertHelper.AssertNetworkStatus("@connectGitLocalRepo");
this.agHelper.GetNClick(this.startUsingGitButton);
this.agHelper.AssertElementExist(this._bottomBarCommit, 0, 30000);
}
if (removeDefaultBranchProtection) {
cy.wait([`@protected-${repoName}`, `@branches-${repoName}`]).then(
(interceptions) => {
if (
interceptions[0]?.response?.statusCode === 200 &&
interceptions[1]?.response?.statusCode === 200
) {
this.clearBranchProtection();
}
},
);
}
cy.wrap(repoName).as("gitRepoName");
});
}
public ImportAppFromGit(
workspaceName: string,
repoName: string,
assertConnect = true,
) {
cy.intercept("GET", "api/v1/git/import/keys?keyType=ECDSA").as(
`importKey-${repoName}`,
);
this.homePage.ImportGitApp(workspaceName);
this.agHelper.GetNClick(this.providerRadioOthers);
this.agHelper.GetNClick(this.existingRepoCheckbox, 0, true);
this.agHelper.GetNClick(this.gitConnectNextBtn);
this.agHelper.AssertAttribute(
this.remoteUrlInput,
"placeholder",
"git@example.com:user/repository.git",
);
this.agHelper.TypeText(
this.remoteUrlInput,
`${this.dataManager.GIT_CLONE_URL}/${repoName}.git`,
);
this.agHelper.GetNClick(this.gitConnectNextBtn);
this.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
cy.wait(`@importKey-${repoName}`).then((result: any) => {
let generatedKey = result.response.body.data.publicKey;
generatedKey = generatedKey.slice(0, generatedKey.length - 1);
// fetch the generated key and post to the github repo
cy.request({
method: "POST",
url: `${this.dataManager.GIT_API_BASE}/api/v1/git/keys/${repoName}`,
body: {
title: "key_" + uid,
key: generatedKey,
read_only: false,
},
}).then((resp: any) => {
cy.log("Deploy Key Id ", resp.body.key_id);
cy.wrap(resp.body.key_id).as("deployKeyId");
});
});
});
this.agHelper.GetNClick(this.addedDeployKeyCheckbox, 0, true);
this.agHelper.GetNClick(this.gitConnectNextBtn);
if (assertConnect) {
this.assertHelper.AssertNetworkStatus("@importFromGit", 201);
}
}
public clearBranchProtection() {
this.agHelper.GetNClick(this._bottomSettingsBtn);
this.agHelper.GetNClick(this._settingsTabBranch);
this.agHelper.GetNClick(this._branchProtectionSelectDropdown);
// const dropdownEl = this.agHelper.GetElement(this._protectedBranchesSelect);
const selectedOptionsEl = this.agHelper.GetElement(
".rc-select-dropdown .rc-select-item-option-active",
);
console.log("ss", selectedOptionsEl);
selectedOptionsEl.each((el) => {
el.trigger("click");
});
this.agHelper.GetNClick(this._branchProtectionUpdateBtn);
this.agHelper.GetNClick(this._closeGitSettingsModal);
}
DeleteTestGithubRepo(repo: any) {
cy.request({
method: "DELETE",
url: `${this.dataManager.GIT_API_BASE}/api/v1/git/repos/${repo}`,
});
}
DeleteDeployKey(repo: any, id: number) {
cy.request({
method: "DELETE",
url: `${this.dataManager.GIT_API_BASE}/api/v1/git/keys/${id}`,
});
}
public CreateRemoteBranch(repo: string, branchName: string) {
cy.request({
method: "POST",
url: `${this.dataManager.GIT_API_BASE}/api/v1/git/repos/${repo}/branches`,
body: {
new_branch_name: branchName,
},
});
}
CreateGitBranch(
branch = "br",
toUseNewGuid = false,
assertCreateBranch = true,
) {
this.agHelper.AssertElementVisibility(this._bottomBarPull);
if (toUseNewGuid) this.agHelper.GenerateUUID();
this.agHelper.AssertElementExist(this._bottomBarCommit);
cy.waitUntil(
() => {
this.agHelper.GetNClick(this._branchButton, 0, true);
if (this.agHelper.IsElementVisible(this._branchSearchInput)) {
return true; //visible, return true to stop waiting
}
return false; //not visible, return false to continue waiting
},
{ timeout: Cypress.config("pageLoadTimeout") },
);
cy.get("@guid").then((uid) => {
//using the same uid as generated during CreateNConnectToGit
this.agHelper.TypeText(
this._branchSearchInput,
`{selectall}` + `${branch + uid}` + `{enter}`,
{ parseSpecialCharSeq: true },
);
assertCreateBranch &&
this.assertHelper.AssertNetworkStatus("createBranch", 201);
this.agHelper.AssertElementAbsence(
this.locator._specificToast(createMessage(UNABLE_TO_IMPORT_APP)),
);
this.agHelper.WaitUntilEleAppear(this._branchName(branch + uid));
this.agHelper.AssertElementVisibility(this._branchName(branch + uid));
this.assertHelper.AssertNetworkStatus("getBranch");
cy.wrap(branch + uid).as("gitbranchName");
});
}
SwitchGitBranch(branch: string, expectError = false, refreshList = false) {
this.agHelper.AssertElementExist(this._bottomBarPull);
this.agHelper.GetNClick(this._branchButton);
if (refreshList) {
this.agHelper.GetNClick(this._gitSyncBranches);
}
this.agHelper.TypeText(
this._branchSearchInput,
`{selectall}` + `${branch}`,
{ parseSpecialCharSeq: true },
);
cy.wait(1000);
// this slows down the checkout api by 1 sec
cy.intercept(
{
method: "GET",
url: "/api/v1/git/checkout-branch/app/**",
},
async (req) => {
return new Promise((resolve) => {
setTimeout(() => resolve(req.continue()), 1000);
});
},
).as("gitCheckoutAPI");
//cy.get(gitSyncLocators.branchListItem).contains(branch).click();
this.agHelper.GetNClickByContains(this._branchListItem, branch);
// checks if the spinner exists
cy.get(`div${this._branchListItem} ${this.locator._btnSpinner}`, {
timeout: 500,
}).should("exist");
cy.wait("@gitCheckoutAPI");
if (!expectError) {
// increasing timeout to reduce flakyness
cy.get(this.locator._btnSpinner, { timeout: 45000 }).should("exist");
cy.get(this.locator._btnSpinner, { timeout: 45000 }).should("not.exist");
}
this.agHelper.Sleep(2000);
}
CheckMergeConflicts(destinationBranch: string) {
this.agHelper.AssertElementExist(this._bottomBarPull);
this.agHelper.GetNClick(this._bottomBarMergeButton);
cy.wait(2000);
this.agHelper.GetNClick(this._mergeBranchDropdownDestination);
// cy.get(commonLocators.dropdownmenu).contains(destinationBranch).click();
this.agHelper.GetNClickByContains(this._dropdownmenu, destinationBranch);
this.agHelper.AssertElementAbsence(this._checkMergeability, 35000);
}
MergeToMaster() {
this.CheckMergeConflicts("master");
this.agHelper.AssertElementEnabledDisabled(this.mergeCTA, 0, false);
this.agHelper.GetNClick(this.mergeCTA);
this.assertHelper.AssertNetworkStatus("@mergeBranch");
this.agHelper.AssertContains(
Cypress.env("MESSAGES").MERGED_SUCCESSFULLY(),
"be.visible",
);
this.CloseGitSyncModal();
}
OpenRepositoryAndVerify() {
this.agHelper.GetNClick(this._openRepoButton);
}
CommitAndPush(assertSuccess = true) {
this.agHelper.GetNClick(this.locator._publishButton);
this.agHelper.AssertElementExist(this._bottomBarPull);
//cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit");
this.agHelper.TypeText(this._commitCommentInput, "Initial commit");
this.agHelper.GetNClick(this._commitButton);
if (assertSuccess) {
// check for commit success
//adding timeout since commit is taking longer sometimes
this.assertHelper.AssertNetworkStatus("@commit", 201);
cy.wait(3000);
} else {
cy.wait("@commit", { timeout: 35000 }).then((interception: any) => {
const status = interception.response.body.responseMeta.status;
expect(status).to.be.gte(400);
});
}
this.CloseGitSyncModal();
}
public DiscardChanges() {
this.agHelper.GetNClick(this._bottomBarCommit);
this.agHelper.AssertElementVisibility(this._gitSyncModal);
this.agHelper.AssertElementVisibility(this._discardChanges);
this.agHelper.ClickButton("Discard & pull");
this.agHelper.AssertContains(
Cypress.env("MESSAGES").DISCARD_CHANGES_WARNING(),
);
this.agHelper.ClickButton("Are you sure?", { waitAfterClick: false });
this.agHelper.AssertContains(
Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES(),
);
this.agHelper.AssertContains("Discarded changes successfully");
this.assertHelper.AssertNetworkStatus("@discardChanges");
this.assertHelper.AssertNetworkStatus("@gitStatus");
this.agHelper.AssertElementExist(this._bottomBarCommit, 0, 30000);
}
public VerifyChangeLog(uncommitedChanges = false) {
// open gitsync modal and verify no uncommited changes exist
this.agHelper.GetNClick(this._bottomBarCommit);
this.agHelper.AssertElementVisibility(this._gitSyncModal);
if (uncommitedChanges) {
this.agHelper.AssertElementEnabledDisabled(
this._commitCommentInput,
0,
false,
);
} else {
this.agHelper.AssertElementEnabledDisabled(
this._commitCommentInput,
0,
true,
);
}
this.CloseGitSyncModal();
}
}