Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Update e2e for patches
Sebastian Martinez committed 3 years ago
commit 78388e9fe24c2986a09eab242cbef8d914d70565
parent 55057564fadf6072b640b147ac90e60bd524ad5b
9 files changed +253 -9
modified cypress.config.cjs
@@ -4,6 +4,7 @@ const { startDevServer } = require('@cypress/vite-dev-server');

module.exports = defineConfig({
  video: false,
+
  defaultCommandTimeout: 10000,
  e2e: {
    setupNodeEvents(on, config) {
      return require('@cypress/code-coverage/task')(on, config);
@@ -27,5 +28,6 @@ module.exports = defineConfig({

    },
    specPattern: 'src/**/*spec.ts',
+
    indexHtmlFile: './index.html'
  },
});
modified cypress/e2e/connect.spec.ts
@@ -10,8 +10,8 @@ describe("MetaMask", () => {
    });
    cy.intercept("POST", "https://api.thegraph.com/subgraphs/name/radicle-dev/radicle-orgs-rinkeby", { data: { safe: null } } );
    cy.intercept("https://gateway.ceramic.network/api/v0/streams", { fixture: "ceramicStream.json" });
-
    cy.get("button.connect").click();
-
    cy.get("button.secondary").click();
+
    cy.get("button.connect").should("have.text", "Connect").click();
+
    cy.get("button.secondary").should("have.text", "Connect with Metamask").click();
    cy.get("button.address").should("contain", "3256 – 5721");
    cy.window().then((win) => {
      win.ethereum.changeAccount("0xd3b5586D15140B6f793b260fd90588A0dAefc5B6");
modified cypress/e2e/project.spec.ts
@@ -59,6 +59,7 @@ describe("Project view", () => {
    cy.intercept("https://willow.radicle.garden:8777/v1/projects/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy", { fixture: "projectInfo.json" });
    cy.intercept("https://willow.radicle.garden:8777/v1/projects/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/remotes", { fixture: "projectRemotes.json" });
    cy.intercept("https://willow.radicle.garden:8777/v1/projects/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/issues", { fixture: "projectIssues.json" });
+
    cy.intercept("https://willow.radicle.garden:8777/v1/projects/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/patches", { fixture: "projectPatches.json" });
    cy.intercept("https://willow.radicle.garden:8777/v1/projects/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/tree/56e4e029c294b08546386e1fb706b772c7433c49", { fixture: "projectTree56e4e02.json" });
    cy.intercept("https://willow.radicle.garden:8777/v1/projects/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/tree/cbf5df499ab4f4a908f1756fbe2c236a4530516a", { fixture: "projectTreecbf5df4.json" });
    cy.intercept("https://willow.radicle.garden:8777/v1/projects/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/remotes/hyndc7nx9keq76p1bkw9831arcndeeu3trwsc7kxt3osmpi6j9oeke", { fixture: "projectBranches.json" });
@@ -154,13 +155,31 @@ describe("Project view", () => {
    cy.get("header .summary .text-medium").should("have.text", "initial commit");
    cy.get("header pre.description").should("have.text", "this is the first commit of many");
    cy.get("header .committer").should("have.text", "dabit3");
-
    cy.get("div.changeset-summary").should("have.text", "1 file(s) changed\n    with\n    0 addition(s)\n    and\n    0 deletion(s)");
-
    cy.get("header.file-header:nth-child(1) div.file-data > *")
+
    cy.get("div.changeset-summary").should("have.text", "1 file(s) created, 1 file(s) deleted and 1 file(s) changed\n  with\n  0 addition(s)\n  and\n  0 deletion(s)");
+
    cy.get("header.file-header:nth-child(1) p.file-path")
      .first()
-
      .should("have.text", "README.md")
+
      .should("have.text", "test.md")
      .next()
      .should("have.text", "created");
    cy.get("tr.diff-line td.diff-line-number").contains("16");
    cy.get("tr.diff-line td.diff-line-content").contains("To prevent front-running, the RAD/USDC balances are set through the Uniswap router *proxy* contract");
  });
+

+
  it("Issues button", () => {
+
    cy.get("div.stat.issue-count")
+
      .click();
+
    cy.location().should((location) => {
+
      expect(location.pathname).to.eq('/seeds/willow.radicle.garden/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/remotes/hyndc7nx9keq76p1bkw9831arcndeeu3trwsc7kxt3osmpi6j9oeke/issues');
+
    });
+
    cy.get("div.stat.issue-count").should("have.class", "active");
+
  });
+

+
  it("Patches button", () => {
+
    cy.get("div.stat.patch-count")
+
      .click();
+
    cy.location().should((location) => {
+
      expect(location.pathname).to.eq('/seeds/willow.radicle.garden/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/remotes/hyndc7nx9keq76p1bkw9831arcndeeu3trwsc7kxt3osmpi6j9oeke/patches');
+
    });
+
    cy.get("div.stat.patch-count").should("have.class", "active");
+
  });
});
modified cypress/fixtures/projectCommit.json
@@ -19,10 +19,44 @@
  },
  "diff": {
    "created": [
-
      "README.md"
+
      {
+
        "path": "test.md",
+
        "diff": {
+
          "type": "plain",
+
          "hunks": [
+
            {
+
              "header": "@@ -0,0 +1 @@\n",
+
              "lines": [
+
                {
+
                  "type": "addition",
+
                  "line": "Hello world\n",
+
                  "lineNum": 1
+
                }
+
              ]
+
            }
+
          ]
+
        }
+
      }
    ],
    "deleted": [
-
      "LICENSE"
+
      {
+
        "path": "test.md",
+
        "diff": {
+
          "type": "plain",
+
          "hunks": [
+
            {
+
              "header": "@@ -0,0 +1 @@\n",
+
              "lines": [
+
                {
+
                  "type": "addition",
+
                  "line": "Hello world\n",
+
                  "lineNum": 1
+
                }
+
              ]
+
            }
+
          ]
+
        }
+
      }
    ],
    "moved": [],
    "copied": [],
modified cypress/fixtures/projectIssues.json
@@ -1 +1,86 @@
-
[]
+
[
+
  {
+
    "id": "hnrk8qmheqbwxius3brqxohqrfmgdrphtirxo",
+
    "author": {
+
      "peer": "hyyg555wwkkutaysg6yr67qnu5d5ji54iur3n5uzzszndh8dp7ofue",
+
      "urn": "rad:git:hnrk81wcokr48mkm544kh74kc9fqz84d3rfcy",
+
      "profile": {
+
        "name": "sebastinez",
+
        "ens": {
+
          "name": "sebastinez.radicle.eth"
+
        }
+
      }
+
    },
+
    "title": "Testing strategy",
+
    "state": {
+
      "status": "open"
+
    },
+
    "comment": {
+
      "author": {
+
        "peer": "hyyg555wwkkutaysg6yr67qnu5d5ji54iur3n5uzzszndh8dp7ofue",
+
        "urn": "rad:git:hnrk81wcokr48mkm544kh74kc9fqz84d3rfcy",
+
        "profile": {
+
          "name": "sebastinez",
+
          "ens": {
+
            "name": "sebastinez.radicle.eth"
+
          }
+
        }
+
      },
+
      "body": "We should define the scope we want to test in integration vs component testing (I don't mention E2E here on purpose since in our E2E tests we stubbed all responses and never hit a real server which equals to integration testing).\n\nWhile integration testing allows us to traverse the application and test navigation, component testing allows us to mount a component in isolation and check all the possible edge cases and possible regressions, and unit testing goes one step further to just individual functions on their correctness.\n\nIntegration testing npm run test:e2e eventually should be npm run test:integration\n\n**Connection through mocked Web3Provider**\n- Navigation through different URLs (e.g. the project pages, commits, issues, patches, etc.)\n- Assert the URLs we're hitting and that they update correctly, when state changes\n- Assert the least amount of display logic (we should leave that to component testing)\n  If we are able to navigate to the correct URL and get the correct props, we shouldn't need to assert every piece of text.\nComponent testing npm run test:components\n\n- Assert the correct rendering\n- Test that the state of the component updates accordingly where applicable.\n**Unit tests npm run test:unit**\n\n- Util functions\nClasses (static and methods)\nI'll keep updating this issue.\nP.S.: Testing is not my expertise so any feedback is welcome.",
+
      "reactions": {
+

+
      },
+
      "replies": null,
+
      "timestamp": 1656509367
+
    },
+
    "discussion": [
+

+
    ],
+
    "labels": [
+
      "discussion"
+
    ],
+
    "timestamp": 1656509367
+
  },
+
  {
+
    "id": "hnrkj4c35uoyceb3d1dsscx8qq55cikrd1aio",
+
    "author": {
+
      "peer": "hyyg555wwkkutaysg6yr67qnu5d5ji54iur3n5uzzszndh8dp7ofue",
+
      "urn": "rad:git:hnrk81wcokr48mkm544kh74kc9fqz84d3rfcy",
+
      "profile": {
+
        "name": "sebastinez",
+
        "ens": {
+
          "name": "sebastinez.radicle.eth"
+
        }
+
      }
+
    },
+
    "title": "Update README",
+
    "state": {
+
      "status": "closed"
+
    },
+
    "comment": {
+
      "author": {
+
        "peer": "hyyg555wwkkutaysg6yr67qnu5d5ji54iur3n5uzzszndh8dp7ofue",
+
        "urn": "rad:git:hnrk81wcokr48mkm544kh74kc9fqz84d3rfcy",
+
        "profile": {
+
          "name": "sebastinez",
+
          "ens": {
+
            "name": "sebastinez.radicle.eth"
+
          }
+
        }
+
      },
+
      "body": "We should define the scope we want to test in integration vs component testing (I don't mention E2E here on purpose since in our E2E tests we stubbed all responses and never hit a real server which equals to integration testing).\n\nWhile integration testing allows us to traverse the application and test navigation, component testing allows us to mount a component in isolation and check all the possible edge cases and possible regressions, and unit testing goes one step further to just individual functions on their correctness.\n\nIntegration testing npm run test:e2e eventually should be npm run test:integration\n\n**Connection through mocked Web3Provider**\n- Navigation through different URLs (e.g. the project pages, commits, issues, patches, etc.)\n- Assert the URLs we're hitting and that they update correctly, when state changes\n- Assert the least amount of display logic (we should leave that to component testing)\n  If we are able to navigate to the correct URL and get the correct props, we shouldn't need to assert every piece of text.\nComponent testing npm run test:components\n\n- Assert the correct rendering\n- Test that the state of the component updates accordingly where applicable.\n**Unit tests npm run test:unit**\n\n- Util functions\nClasses (static and methods)\nI'll keep updating this issue.\nP.S.: Testing is not my expertise so any feedback is welcome.",
+
      "reactions": {
+

+
      },
+
      "replies": null,
+
      "timestamp": 1656509367
+
    },
+
    "discussion": [
+

+
    ],
+
    "labels": [
+
      "discussion"
+
    ],
+
    "timestamp": 1656509367
+
  }
+
]
added cypress/fixtures/projectPatches.json
@@ -0,0 +1,90 @@
+
[
+
  {
+
    "id": "hnrkj4c35uoyceb3d1dsscx8qq55cikrd1aio",
+
    "author": {
+
      "peer": "hybepksbf5xzew3ztear7k7peddho5wfts3d8uyb9pcdu6sqgnwqak",
+
      "urn": "rad:git:hnrkkxqo5jgx3bwbphdsmqyk9djkfr368czio",
+
      "profile": {
+
        "name": "Scooby",
+
        "ens": null
+
      }
+
    },
+
    "title": "this is a patch with multiple commits and a merge base",
+
    "state": "proposed",
+
    "target": "upstream",
+
    "labels": [],
+
    "revisions": [
+
      {
+
        "id": "d2a46e1f-88a9-4e72-bc68-3f6afc92003c",
+
        "peer": "hybepksbf5xzew3ztear7k7peddho5wfts3d8uyb9pcdu6sqgnwqak",
+
        "base": "58c1864cb6c6edd8682830d087bdcef7902cf62a",
+
        "oid": "a36d8df141a0d3cedf47c4a42383ed98818195de",
+
        "comment": {
+
          "author": {
+
            "peer": "hybepksbf5xzew3ztear7k7peddho5wfts3d8uyb9pcdu6sqgnwqak",
+
            "urn": "rad:git:hnrkkxqo5jgx3bwbphdsmqyk9djkfr368czio",
+
            "profile": {
+
              "name": "Scooby",
+
              "ens": null
+
            }
+
          },
+
          "body": "Signed-off-by: Sebastian Martinez <me@sebastinez.dev>",
+
          "reactions": {
+

+
          },
+
          "replies": null,
+
          "timestamp": 1656666433
+
        },
+
        "discussion": [],
+
        "reviews": {},
+
        "merges": [],
+
        "changeset": null,
+
        "timestamp": 1656666433
+
      }
+
    ],
+
    "timestamp": 1656666433
+
  },
+
  {
+
    "id": "hnrkqjf6ucd3o8ffztt7yyeatuj9u4k4957xo",
+
    "author": {
+
      "peer": "hybepksbf5xzew3ztear7k7peddho5wfts3d8uyb9pcdu6sqgnwqak",
+
      "urn": "rad:git:hnrkkxqo5jgx3bwbphdsmqyk9djkfr368czio",
+
      "profile": {
+
        "name": "Scooby",
+
        "ens": null
+
      }
+
    },
+
    "title": "Removing files",
+
    "state": "proposed",
+
    "target": "upstream",
+
    "labels": [],
+
    "revisions": [
+
      {
+
        "id": "7edbb9df-e921-4dff-b2e2-5b0a50c51188",
+
        "peer": "hybepksbf5xzew3ztear7k7peddho5wfts3d8uyb9pcdu6sqgnwqak",
+
        "base": "58c1864cb6c6edd8682830d087bdcef7902cf62a",
+
        "oid": "6da5af5cf09b5db638b8a6f5ce386391c3b74da4",
+
        "comment": {
+
          "author": {
+
            "peer": "hybepksbf5xzew3ztear7k7peddho5wfts3d8uyb9pcdu6sqgnwqak",
+
            "urn": "rad:git:hnrkkxqo5jgx3bwbphdsmqyk9djkfr368czio",
+
            "profile": {
+
              "name": "Scooby",
+
              "ens": null
+
            }
+
          },
+
          "body": "Signed-off-by: Sebastian Martinez <me@sebastinez.dev>",
+
          "reactions": {},
+
          "replies": null,
+
          "timestamp": 1656667614
+
        },
+
        "discussion": [],
+
        "reviews": {},
+
        "merges": [],
+
        "changeset": null,
+
        "timestamp": 1656667614
+
      }
+
    ],
+
    "timestamp": 1656667614
+
  }
+
]
modified cypress/support/component.ts
@@ -1 +1,5 @@
import '@testing-library/cypress/add-commands';
+
import { Buffer } from "buffer";
+

+
//@ts-expect-error We need Buffer on the window object in the test env for component testing
+
window.Buffer = Buffer;
modified cypress/support/e2e.ts
@@ -3,6 +3,7 @@ import '@cypress/code-coverage/support';
import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers';
import '@testing-library/cypress/add-commands';
import { BigNumber, ethers } from 'ethers';
+
import { Resolver } from "@ethersproject/providers";

declare global {
  interface Window {
@@ -29,6 +30,15 @@ export class MockExtensionProvider extends ethers.providers.BaseProvider {
    return new JsonRpcSigner({}, this as unknown as JsonRpcProvider, addressOrIndex);
  }

+
  async getResolver(name: string): Promise<null | Resolver> {
+
    const address = "0x5E813e48a81977c6Fdd565ed5097eb600C73C4f0";
+
    return new Resolver(this, address, name, address);
+
  }
+

+
  async lookupAddress(address: string | Promise<string>): Promise<string | null> {
+
    return "mock.eth";
+
  }
+

  changeAccount(address: string): void {
    this.currentAddress = address;
    this.emit("accountsChanged", [address]);
modified vite.config.ts
@@ -66,7 +66,7 @@ const config: UserConfig = {
};

// For Vitest to work we need to unset READABLE_STREAM.
-
if (process.env.VITEST) {
+
if (process.env.VITEST || process.env.Cypress) {
  config.define = undefined;
}