diff --git a/webui/src/pages/repositories/repository/pulls/pullsList.jsx b/webui/src/pages/repositories/repository/pulls/pullsList.jsx index 6c732bdc1bd..178baf27402 100644 --- a/webui/src/pages/repositories/repository/pulls/pullsList.jsx +++ b/webui/src/pages/repositories/repository/pulls/pullsList.jsx @@ -81,7 +81,7 @@ const PullsList = ({repo, after, prefix, onPaginate}) => { else content = (results && !!results.length ? <> - + {results.map(pull => ( ))} diff --git a/webui/test/e2e/common/quickstart.spec.ts b/webui/test/e2e/common/quickstart.spec.ts index ab60d011c3b..f92134e08fc 100644 --- a/webui/test/e2e/common/quickstart.spec.ts +++ b/webui/test/e2e/common/quickstart.spec.ts @@ -2,101 +2,137 @@ import { test, expect } from "@playwright/test"; import { RepositoriesPage } from "../poms/repositoriesPage"; import { RepositoryPage } from "../poms/repositoryPage"; import { ObjectViewerPage } from "../poms/objectViewerPage"; +import { PullsPage } from "../poms/pullsPage"; const QUICKSTART_REPO_NAME = "quickstart"; const PARQUET_OBJECT_NAME = "lakes.parquet"; const NEW_BRANCH_NAME = "denmark-lakes"; const SELECT_QUERY = - "SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/main/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;"; + "SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/main/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;"; const CREATE_TABLE_QUERY = - "CREATE OR REPLACE TABLE lakes AS SELECT * FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet');"; + "CREATE OR REPLACE TABLE lakes AS SELECT * FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet');"; const DELETE_QUERY = "DELETE FROM lakes WHERE Country != 'Denmark';"; const COPY_QUERY = - "COPY lakes TO 'lakefs://quickstart/denmark-lakes/lakes.parquet';"; + "COPY lakes TO 'lakefs://quickstart/denmark-lakes/lakes.parquet';"; const SELECT_NEW_BRANCH = - "DROP TABLE lakes; SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;"; + "DROP TABLE lakes; SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;"; test.describe("Quickstart", () => { - test.describe.configure({ mode: "serial" }); - test("create repo w/ sample data", async ({ page }) => { - const repositoriesPage = new RepositoriesPage(page); - await repositoriesPage.goto(); - await repositoriesPage.createRepository(QUICKSTART_REPO_NAME, true); - }); - - test("view and query parquet object", async ({ page }) => { - const repositoriesPage = new RepositoriesPage(page); - await repositoriesPage.goto(); - await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); - - const repositoryPage = new RepositoryPage(page); - await repositoryPage.clickObject(PARQUET_OBJECT_NAME); - await expect(page.getByText("Loading...")).not.toBeVisible(); - - const objectViewerPage = new ObjectViewerPage(page); - await objectViewerPage.enterQuery(SELECT_QUERY); - await objectViewerPage.clickExecuteButton(); - await expect(await objectViewerPage.getResultRowCount()).toEqual(5); - }); - - test("transforming data", async ({ page }) => { - const repositoriesPage = new RepositoriesPage(page); - await repositoriesPage.goto(); - await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); - - const repositoryPage = new RepositoryPage(page); - await repositoryPage.createBranch(NEW_BRANCH_NAME); - - await repositoryPage.gotoObjectsTab(); - await repositoryPage.clickObject(PARQUET_OBJECT_NAME); - await expect(page.getByText("Loading...")).not.toBeVisible(); - - const objectViewerPage = new ObjectViewerPage(page); - await objectViewerPage.enterQuery(CREATE_TABLE_QUERY); - await objectViewerPage.clickExecuteButton(); - - await objectViewerPage.enterQuery(DELETE_QUERY); - await objectViewerPage.clickExecuteButton(); - - await objectViewerPage.enterQuery(COPY_QUERY); - await objectViewerPage.clickExecuteButton(); - - await objectViewerPage.enterQuery(SELECT_NEW_BRANCH); - await objectViewerPage.clickExecuteButton(); - await expect(await objectViewerPage.getResultRowCount()).toEqual(1); - }); - - test("commit and merge", async ({ page }) => { - const repositoriesPage = new RepositoriesPage(page); - await repositoriesPage.goto(); - await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); - - const repositoryPage = new RepositoryPage(page); - await repositoryPage.gotoUncommittedChangeTab(); - await repositoryPage.switchBranch(NEW_BRANCH_NAME); - await expect( - await page.getByText("Showing changes for branch") - ).toBeVisible(); - await expect(await repositoryPage.getUncommittedCount()).toEqual(1); - - await repositoryPage.commitChanges("denmark"); - await expect(page.getByText("No changes")).toBeVisible(); - - await repositoryPage.gotoCompareTab(); - await repositoryPage.switchBaseBranch("main"); - await expect(await page.getByText("Showing changes between")).toBeVisible(); - await expect(await repositoryPage.getUncommittedCount()).toEqual(1); - await repositoryPage.merge("merge commit"); - await expect(page.getByText("No changes")).toBeVisible(); - - await repositoriesPage.goto(); - await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); - await repositoryPage.clickObject(PARQUET_OBJECT_NAME); - await expect(page.getByText("Loading...")).not.toBeVisible(); - const objectViewerPage = new ObjectViewerPage(page); - await objectViewerPage.enterQuery(SELECT_QUERY); - await objectViewerPage.clickExecuteButton(); - await expect(await objectViewerPage.getResultRowCount()).toEqual(1); - }); + test.describe.configure({mode: "serial"}); + test("create repo w/ sample data", async ({page}) => { + const repositoriesPage = new RepositoriesPage(page); + await repositoriesPage.goto(); + await repositoriesPage.createRepository(QUICKSTART_REPO_NAME, true); + }); + + test("view and query parquet object", async ({page}) => { + const repositoriesPage = new RepositoriesPage(page); + await repositoriesPage.goto(); + await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); + + const repositoryPage = new RepositoryPage(page); + await repositoryPage.clickObject(PARQUET_OBJECT_NAME); + await expect(page.getByText("Loading...")).not.toBeVisible(); + + const objectViewerPage = new ObjectViewerPage(page); + await objectViewerPage.enterQuery(SELECT_QUERY); + await objectViewerPage.clickExecuteButton(); + await expect(await objectViewerPage.getResultRowCount()).toEqual(5); + }); + + test("transforming data", async ({page}) => { + const repositoriesPage = new RepositoriesPage(page); + await repositoriesPage.goto(); + await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); + + const repositoryPage = new RepositoryPage(page); + await repositoryPage.createBranch(NEW_BRANCH_NAME); + + await repositoryPage.gotoObjectsTab(); + await repositoryPage.clickObject(PARQUET_OBJECT_NAME); + await expect(page.getByText("Loading...")).not.toBeVisible(); + + const objectViewerPage = new ObjectViewerPage(page); + await objectViewerPage.enterQuery(CREATE_TABLE_QUERY); + await objectViewerPage.clickExecuteButton(); + + await objectViewerPage.enterQuery(DELETE_QUERY); + await objectViewerPage.clickExecuteButton(); + + await objectViewerPage.enterQuery(COPY_QUERY); + await objectViewerPage.clickExecuteButton(); + + await objectViewerPage.enterQuery(SELECT_NEW_BRANCH); + await objectViewerPage.clickExecuteButton(); + await expect(await objectViewerPage.getResultRowCount()).toEqual(1); + }); + + test("commit and merge", async ({page}) => { + const repositoriesPage = new RepositoriesPage(page); + await repositoriesPage.goto(); + await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); + + const repositoryPage = new RepositoryPage(page); + await repositoryPage.gotoUncommittedChangeTab(); + await repositoryPage.switchBranch(NEW_BRANCH_NAME); + await expect( + await page.getByText("Showing changes for branch") + ).toBeVisible(); + await expect(await repositoryPage.getUncommittedCount()).toEqual(1); + + await repositoryPage.commitChanges("denmark"); + await expect(page.getByText("No changes")).toBeVisible(); + + await repositoryPage.gotoCompareTab(); + await repositoryPage.switchBaseBranch("main"); + await expect(await page.getByText("Showing changes between")).toBeVisible(); + await expect(await repositoryPage.getUncommittedCount()).toEqual(1); + await repositoryPage.merge("merge commit"); + await expect(page.getByText("No changes")).toBeVisible(); + + await repositoriesPage.goto(); + await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); + await repositoryPage.clickObject(PARQUET_OBJECT_NAME); + await expect(page.getByText("Loading...")).not.toBeVisible(); + const objectViewerPage = new ObjectViewerPage(page); + await objectViewerPage.enterQuery(SELECT_QUERY); + await objectViewerPage.clickExecuteButton(); + await expect(await objectViewerPage.getResultRowCount()).toEqual(1); + }); + + test("pull requests", async ({page}) => { + const repositoriesPage = new RepositoriesPage(page); + await repositoriesPage.goto(); + await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME); + + const branchNameForPull = "branch-for-pull-1"; + const commitMsg = "commit-for-pull-1"; + + const repositoryPage = new RepositoryPage(page); + + await repositoryPage.gotoObjectsTab(); + await repositoryPage.switchBranch(branchNameForPull); + await repositoryPage.deleteFirstFileInDirectory("images/"); + + await repositoryPage.gotoUncommittedChangeTab(); + expect(await repositoryPage.getUncommittedCount()).toEqual(1); + await repositoryPage.commitChanges(commitMsg); + await expect(page.getByText("No changes")).toBeVisible(); + + await repositoryPage.gotoPullRequestsTab(); + await expect(page.getByText("Create Pull Request")).toBeVisible(); + const pullsPage = new PullsPage(page); + expect(await pullsPage.getPullsListCount()).toEqual(0); + + await pullsPage.clickCreatePullButton(); + await expect(page.getByRole("heading", {name: "Create Pull Request"})).toBeVisible(); + await pullsPage.switchCompareBranch(branchNameForPull); + const titleForPull1 = "PR for branch 1"; + await pullsPage.fillPullTitle(titleForPull1); + await pullsPage.clickCreatePullButton(); + await expect(page.getByRole("heading", {name: titleForPull1})).toBeVisible(); + + await expect(page.locator("div.lakefs-uri").getByText(`main...${branchNameForPull}`)).toBeVisible(); + }); }); diff --git a/webui/test/e2e/poms/pullsPage.ts b/webui/test/e2e/poms/pullsPage.ts new file mode 100644 index 00000000000..42ad2de74d6 --- /dev/null +++ b/webui/test/e2e/poms/pullsPage.ts @@ -0,0 +1,38 @@ +import { Page } from "@playwright/test"; + +export class PullsPage { + private page: Page; + + constructor(page: Page) { + this.page = page; + } + + async getPullsListCount(): Promise { + await this.page.locator("div.pulls-list").isVisible(); + return this.page + .locator("div.pulls-list") + .locator("pull-row") + .count(); + } + + async getResultRowCount(): Promise { + return this.page + .locator("table.table") + .locator("tbody") + .locator("tr") + .count(); + } + + async switchCompareBranch(name: string): Promise { + await this.page.getByRole("button", { name: "to branch: " }).click(); + await this.page.getByRole("button", { name }).click(); + } + + async clickCreatePullButton(): Promise { + await this.page.getByRole("button", { name: "Create Pull Request" }).click(); + } + + async fillPullTitle(title: string): Promise { + await this.page.getByPlaceholder("Add a title...").fill(title); + } +} diff --git a/webui/test/e2e/poms/repositoryPage.ts b/webui/test/e2e/poms/repositoryPage.ts index e8190cb89a8..fea761c9d48 100644 --- a/webui/test/e2e/poms/repositoryPage.ts +++ b/webui/test/e2e/poms/repositoryPage.ts @@ -21,6 +21,8 @@ export class RepositoryPage { .click(); } + // branch operations + async createBranch(name: string): Promise { await this.page .getByRole("link", { name: "Branches", exact: false }) @@ -37,6 +39,35 @@ export class RepositoryPage { await this.page.getByRole("button", { name }).click(); } + // file manipulation operations + + async deleteFirstFileInDirectory(dirName: string): Promise { + await this.page.getByRole("link", {name: dirName}).click(); + await this.page + .locator("table.table") + .locator("tbody") + .locator("tr") + .first() + .locator("div.dropdown") + .hover(); + await this.page + .locator("table.table") + .locator("tbody") + .locator("tr") + .first() + .locator("div.dropdown") + .locator("button") + .click(); + await this.page + .locator("div.dropdown") + .locator(".dropdown-item") + .last() + .click(); + await this.page.getByRole("button", {name: "Yes"}).click(); + } + + // uncommitted changes operations + async getUncommittedCount(): Promise { await this.page.locator("div.card").isVisible(); return this.page @@ -57,6 +88,8 @@ export class RepositoryPage { .click(); } + // merge operations + async merge(commitMsg: string): Promise { await this.page.getByRole("button", { name: "Merge" }).click(); if (commitMsg?.length) { @@ -75,6 +108,8 @@ export class RepositoryPage { await this.page.getByRole("button", { name }).click(); } + // navigation + async gotoObjectsTab(): Promise { await this.page.getByRole("link", { name: "Objects" }).click(); } @@ -86,4 +121,8 @@ export class RepositoryPage { async gotoCompareTab(): Promise { await this.page.getByRole("link", { name: "Compare" }).click(); } + + async gotoPullRequestsTab(): Promise { + await this.page.getByRole("link", { name: "Pull Requests" }).click(); + } }