PromucFlow_constructor/app/client/cypress/support/gitSync.js
Ivan Akulov 424d2f6965
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description

This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.

As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes

This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)

### Why is this needed?

This PR is needed because, for the Lodash optimization from
7cbb12af88,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.

However, just using `import type` in the current codebase will give you
this:

<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">

That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.

### Why enforce `import type`?

Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)

I’m doing this because I believe `import type` improves DX and makes
refactorings easier.

Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)

```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```

It’s pretty hard, right?

What about now?

```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```

Now, it’s clear that only `lodash` will be bundled.

This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.

This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.

## Type of change

- Chore (housekeeping or task changes that don't impact user perception)


## How Has This Been Tested?

This was tested to not break the build.

### Test Plan
> Add Testsmith test cases links that relate to this PR

### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)


## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


### 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: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 17:11:47 +05:30

496 lines
16 KiB
JavaScript

/* eslint-disable cypress/no-unnecessary-waiting */
/* eslint-disable cypress/no-assigning-return-values */
require("cy-verify-downloads").addCustomCommand();
require("cypress-file-upload");
import gitSyncLocators from "../locators/gitSyncLocators";
import homePage from "../locators/HomePage";
import { ObjectsRegistry } from "../support/Objects/Registry";
import datasourceFormData from "../fixtures/datasources.json";
let gitSync = ObjectsRegistry.GitSync,
agHelper = ObjectsRegistry.AggregateHelper;
const commonLocators = require("../locators/commonlocators.json");
const GITHUB_API_BASE = "https://api.github.com";
Cypress.Commands.add("revokeAccessGit", (appName) => {
cy.xpath("//span[text()= `${appName}`]").parent().next().click();
cy.get(gitSyncLocators.disconnectAppNameInput).type(appName);
cy.get(gitSyncLocators.disconnectButton).click();
cy.route("POST", "api/v1/git/disconnect/app/*").as("disconnect");
cy.get(gitSyncLocators.disconnectButton).click();
cy.wait("@disconnect").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
);
cy.window()
.its("store")
.invoke("getState")
.then((state) => {
const { id, name } = state.ui.gitSync.disconnectingGitApp;
expect(name).to.eq("");
expect(id).to.eq("");
});
});
Cypress.Commands.add(
"connectToGitRepo",
(repo, shouldCommit = true, assertConnectFailure) => {
const testEmail = "test@test.com";
const testUsername = "testusername";
const owner = Cypress.env("TEST_GITHUB_USER_NAME");
let generatedKey;
// open gitSync modal
cy.get(homePage.deployPopupOptionTrigger).click();
cy.get(homePage.connectToGitBtn).click({ force: true });
// cy.intercept(
// {
// url: "api/v1/git/connect/app/*",
// hostname: window.location.host,
// },
// (req) => {
// req.headers["origin"] = "Cypress";
// },
// );
cy.intercept("POST", "/api/v1/applications/ssh-keypair/*").as(
`generateKey-${repo}`,
);
cy.get(gitSyncLocators.gitRepoInput).type(
`git@github.com:${owner}/${repo}.git`,
);
cy.get(gitSyncLocators.generateDeployKeyBtn).click();
cy.wait(`@generateKey-${repo}`).then((result) => {
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: `${GITHUB_API_BASE}/repos/${Cypress.env(
"TEST_GITHUB_USER_NAME",
)}/${repo}/keys`,
headers: {
Authorization: `token ${Cypress.env("GITHUB_PERSONAL_ACCESS_TOKEN")}`,
},
body: {
title: "key0",
key: generatedKey,
},
});
cy.get(gitSyncLocators.useGlobalGitConfig).click();
cy.get(gitSyncLocators.gitConfigNameInput).type(
`{selectall}${testUsername}`,
);
cy.get(gitSyncLocators.gitConfigEmailInput).type(
`{selectall}${testEmail}`,
);
// click on the connect button and verify
cy.get(gitSyncLocators.connectSubmitBtn).click();
if (!assertConnectFailure) {
// check for connect success
cy.wait("@connectGitLocalRepo").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
);
}
// click commit button
/* if (shouldCommit) {
cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit");
cy.get(gitSyncLocators.commitButton).click();
// check for commit success
cy.wait("@commit").should(
"have.nested.property",
"response.body.responseMeta.status",
201,
);
cy.get(gitSyncLocators.closeGitSyncModal).click();
}
} else {
cy.wait("@connectGitLocalRepo").then((interception) => {
const status = interception.response.body.responseMeta.status;
expect(status).to.be.gte(400);
});
} */
cy.get(gitSyncLocators.closeGitSyncModal).click();
});
},
);
Cypress.Commands.add("latestDeployPreview", () => {
cy.server();
cy.route("POST", "/api/v1/applications/publish/*").as("publishApp");
// Wait before publish
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000);
cy.assertPageSave();
// Stubbing window.open to open in the same tab
cy.window().then((window) => {
cy.stub(window, "open").callsFake((url) => {
window.location.href = Cypress.config().baseUrl + url.substring(1);
window.location.target = "_self";
});
});
cy.get(gitSyncLocators.bottomBarCommitButton).click();
cy.xpath("//span[text()='Latest deployed preview']").click();
cy.log("pagename: " + localStorage.getItem("PageName"));
cy.wait(2000); //wait time for page to load!
});
Cypress.Commands.add("createGitBranch", (branch) => {
cy.get(gitSyncLocators.branchButton).click({ force: true });
cy.wait(3000);
cy.get(gitSyncLocators.branchSearchInput).type(`{selectall}${branch}{enter}`);
// increasing timeout to reduce flakyness
cy.get(".bp3-spinner", { timeout: 30000 }).should("exist");
cy.get(".bp3-spinner", { timeout: 30000 }).should("not.exist");
});
Cypress.Commands.add("switchGitBranch", (branch, expectError) => {
agHelper.AssertElementExist(gitSync._bottomBarPull);
cy.get(gitSyncLocators.branchButton).click({ force: true });
cy.get(gitSyncLocators.branchSearchInput).type(`{selectall}${branch}`);
cy.wait(1000);
cy.get(gitSyncLocators.branchListItem).contains(branch).click();
if (!expectError) {
// increasing timeout to reduce flakyness
cy.get(".bp3-spinner", { timeout: 30000 }).should("exist");
cy.get(".bp3-spinner", { timeout: 30000 }).should("not.exist");
}
cy.wait(2000);
});
Cypress.Commands.add("createTestGithubRepo", (repo, privateFlag = false) => {
cy.request({
method: "POST",
url: `${GITHUB_API_BASE}/user/repos`,
headers: {
Authorization: `token ${Cypress.env("GITHUB_PERSONAL_ACCESS_TOKEN")}`,
},
body: {
name: repo,
private: privateFlag,
},
});
});
Cypress.Commands.add("mergeViaGithubApi", ({ base, head, repo }) => {
const owner = Cypress.env("TEST_GITHUB_USER_NAME");
cy.request({
method: "POST",
url: `${GITHUB_API_BASE}/repos/${owner}/${repo}/merges`,
headers: {
Authorization: `token ${Cypress.env("GITHUB_PERSONAL_ACCESS_TOKEN")}`,
},
body: {
base,
head,
},
});
});
Cypress.Commands.add("deleteTestGithubRepo", (repo) => {
cy.request({
method: "DELETE",
url: `${GITHUB_API_BASE}/repos/${Cypress.env(
"TEST_GITHUB_USER_NAME",
)}/${repo}`,
headers: {
Authorization: `token ${Cypress.env("GITHUB_PERSONAL_ACCESS_TOKEN")}`,
},
});
});
Cypress.Commands.add(
"renameBranchViaGithubApi",
(repo, currentName, newName) => {
cy.request({
method: "POST",
url: `${GITHUB_API_BASE}/repos/${Cypress.env(
"TEST_GITHUB_USER_NAME",
)}/${repo}/branches/${currentName}/rename`,
headers: {
Authorization: `token ${Cypress.env("GITHUB_PERSONAL_ACCESS_TOKEN")}`,
},
body: {
new_name: newName,
},
});
},
);
Cypress.Commands.add("commitAndPush", (assertFailure) => {
cy.get(homePage.publishButton).click();
agHelper.AssertElementExist(gitSync._bottomBarPull);
cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit");
cy.get(gitSyncLocators.commitButton).click();
if (!assertFailure) {
// check for commit success
//adding timeout since commit is taking longer sometimes
cy.wait("@commit", { timeout: 35000 }).should(
"have.nested.property",
"response.body.responseMeta.status",
201,
);
cy.wait(3000);
} else {
cy.wait("@commit", { timeout: 35000 }).then((interception) => {
const status = interception.response.body.responseMeta.status;
expect(status).to.be.gte(400);
});
}
cy.get(gitSyncLocators.closeGitSyncModal).click();
});
// todo rishabh s: refactor
Cypress.Commands.add(
"createAppAndConnectGit",
(appname, shouldConnect = true, assertConnectFailure) => {
cy.get(homePage.homeIcon).click({ force: true });
cy.get(homePage.createNew).first().click({ force: true });
cy.wait("@createNewApplication").should(
"have.nested.property",
"response.body.responseMeta.status",
201,
);
cy.get("#loading").should("not.exist");
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000);
cy.AppSetupForRename();
cy.get(homePage.applicationName).type(appname + "{enter}");
cy.wait("@updateApplication").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
);
cy.createTestGithubRepo(appname, true);
cy.connectToGitRepo(appname, false, assertConnectFailure);
cy.get(gitSyncLocators.closeGitSyncModal).click({ force: true });
},
);
Cypress.Commands.add("merge", (destinationBranch) => {
agHelper.AssertElementExist(gitSync._bottomBarPull);
cy.get(gitSyncLocators.bottomBarMergeButton).click();
//cy.wait(6000); // wait for git status call to finish
/*cy.wait("@gitStatus").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
); */
agHelper.AssertElementEnabledDisabled(
gitSyncLocators.mergeBranchDropdownDestination,
0,
false,
);
cy.wait(3000);
cy.get(gitSyncLocators.mergeBranchDropdownDestination).click();
cy.get(commonLocators.dropdownmenu).contains(destinationBranch).click();
agHelper.AssertElementAbsence(gitSync._checkMergeability, 35000);
cy.wait("@mergeStatus", { timeout: 35000 }).should(
"have.nested.property",
"response.body.data.isMergeAble",
true,
);
cy.wait(2000);
cy.contains(Cypress.env("MESSAGES").NO_MERGE_CONFLICT());
cy.get(gitSyncLocators.mergeCTA).click();
cy.wait("@mergeBranch", { timeout: 35000 }).should(
"have.nested.property",
"response.body.responseMeta.status",
200,
); //adding timeout since merge is taking longer sometimes
cy.contains(Cypress.env("MESSAGES").MERGED_SUCCESSFULLY());
});
Cypress.Commands.add(
"importAppFromGit",
(repo, assertConnectFailure, failureMessage) => {
const testEmail = "test@test.com";
const testUsername = "testusername";
const owner = Cypress.env("TEST_GITHUB_USER_NAME");
let generatedKey;
// cy.intercept(
// {
// url: "api/v1/git/connect/app/*",
// hostname: window.location.host,
// },
// (req) => {
// req.headers["origin"] = "Cypress";
// },
// );
cy.intercept("GET", "api/v1/git/import/keys?keyType=ECDSA").as(
`generateKey-${repo}`,
);
cy.get(gitSyncLocators.gitRepoInput).type(
//`git@github.com:${owner}/${repo}.git`,
`${datasourceFormData["GITEA_API_URL_TED"]}/${repo}.git`,
);
cy.get(gitSyncLocators.generateDeployKeyBtn).click();
cy.wait(`@generateKey-${repo}`).then((result) => {
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: `${GITHUB_API_BASE}/repos/${Cypress.env(
// "TEST_GITHUB_USER_NAME",
// )}/${repo}/keys`,
// headers: {
// Authorization: `token ${Cypress.env("GITHUB_PERSONAL_ACCESS_TOKEN")}`,
// },
// body: {
// title: "key0",
// key: generatedKey,
// },
// });
cy.request({
method: "POST",
url: `${datasourceFormData["GITEA_API_BASE_TED"]}:${datasourceFormData["GITEA_API_PORT_TED"]}/api/v1/repos/Cypress/${repo}/keys`,
headers: {
Authorization: `token ${Cypress.env("GITEA_TOKEN")}`,
},
body: {
title: "key1",
key: generatedKey,
read_only: false,
},
});
cy.get(gitSyncLocators.useGlobalGitConfig).click();
cy.get(gitSyncLocators.gitConfigNameInput).type(
`{selectall}${testUsername}`,
);
cy.get(gitSyncLocators.gitConfigEmailInput).type(
`{selectall}${testEmail}`,
);
// click on the connect button and verify
cy.get(gitSyncLocators.connectSubmitBtn).click();
if (!assertConnectFailure) {
// check for connect success
cy.wait("@importFromGit").should(
"have.nested.property",
"response.body.responseMeta.status",
201,
);
} else {
cy.wait("@importFromGit").then((interception) => {
const status = interception.response.body.responseMeta.status;
const message = interception.response.body.responseMeta.error.message;
expect(status).to.be.gte(400);
expect(message).to.contain(failureMessage);
});
}
});
},
);
Cypress.Commands.add("gitDiscardChanges", () => {
cy.get(gitSyncLocators.bottomBarCommitButton).click();
cy.get(gitSyncLocators.discardChanges).should("be.visible");
//cy.wait(6000);
cy.get(gitSyncLocators.discardChanges)
.children()
.should("have.text", "Discard changes");
cy.get(gitSyncLocators.discardChanges).click();
cy.contains(Cypress.env("MESSAGES").DISCARD_CHANGES_WARNING());
cy.get(gitSyncLocators.discardChanges)
.children()
.should("have.text", "Are you sure?");
cy.get(gitSyncLocators.discardChanges).click();
cy.contains(Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES());
cy.wait(2000);
cy.validateToastMessage("Discarded changes successfully.");
});
Cypress.Commands.add(
"regenerateSSHKey",
(repo, generateKey = true, protocol = "ECDSA") => {
let generatedKey;
cy.get(gitSyncLocators.bottomBarCommitButton).click();
cy.get("[data-cy=t--tab-GIT_CONNECTION]").click();
cy.wait(2000);
cy.get(gitSyncLocators.SSHKeycontextmenu).click();
if (protocol === "ECDSA") {
cy.get(gitSyncLocators.regenerateSSHKeyECDSA).click();
} else if (protocol === "RSA") {
cy.get(gitSyncLocators.regenerateSSHKeyRSA).click();
}
cy.contains(Cypress.env("MESSAGES").REGENERATE_KEY_CONFIRM_MESSAGE());
cy.xpath(gitSyncLocators.confirmButton).click();
if (protocol === "ECDSA") {
cy.intercept("POST", "/api/v1/applications/ssh-keypair/*").as(
`generateKey-${repo}`,
);
} else if (protocol === "RSA") {
cy.intercept("POST", "/api/v1/applications/ssh-keypair/*?keyType=RSA").as(
`generateKey-${repo}-RSA`,
);
}
if (generateKey) {
if (protocol === "ECDSA") {
cy.wait(`@generateKey-${repo}`).then((result) => {
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: `${GITHUB_API_BASE}/repos/${Cypress.env(
// "TEST_GITHUB_USER_NAME",
// )}/${repo}/keys`,
// headers: {
// Authorization: `token ${Cypress.env(
// "GITHUB_PERSONAL_ACCESS_TOKEN",
// )}`,
// },
// body: {
// title: "key0",
// key: generatedKey,
// },
// });
cy.request({
method: "POST",
url: `${datasourceFormData["GITEA_API_BASE_TED"]}:${datasourceFormData["GITEA_API_PORT_TED"]}/api/v1/repos/Cypress/${repo}/keys`,
headers: {
Authorization: `token ${Cypress.env("GITEA_TOKEN")}`,
},
body: {
title: "key1",
key: generatedKey,
read_only: false,
},
});
cy.get(gitSyncLocators.closeGitSyncModal);
});
} else if (protocol === "RSA") {
// doesn't work with github
}
}
},
);