diff --git a/documents/QA test file.penpot b/documents/QA test file.penpot new file mode 100644 index 0000000..e903578 Binary files /dev/null and b/documents/QA test file.penpot differ diff --git a/documents/QA test zip file.zip b/documents/QA test zip file.zip new file mode 100644 index 0000000..7cf71c9 Binary files /dev/null and b/documents/QA test zip file.zip differ diff --git a/pages/base-page.js b/pages/base-page.js index 72fa71c..8277bc3 100644 --- a/pages/base-page.js +++ b/pages/base-page.js @@ -4,7 +4,7 @@ exports.BasePage = class BasePage { */ constructor(page) { this.page = page; - this.header = page.locator("h1"); + this.header = page.locator('div[class="dashboard-title"] h1'); } async clearInput(input) { diff --git a/pages/dashboard-page.js b/pages/dashboard-page.js index c784f9a..802aedc 100644 --- a/pages/dashboard-page.js +++ b/pages/dashboard-page.js @@ -55,6 +55,9 @@ exports.DashboardPage = class DashboardPage extends BasePage { this.fileOptionsMenuButton = page.locator( 'div[class="project-th-icon menu"] svg[class="icon-actions"]' ); + this.headerOptionsMenuButton = page.locator( + 'div[class="dashboard-header-actions"] svg[class="icon-actions"]' + ); //Projects this.addProjectButton = page.locator( @@ -81,21 +84,25 @@ exports.DashboardPage = class DashboardPage extends BasePage { this.projectOptionsMenuButton = page.locator( '*[data-test="project-options"] .icon-actions' ); + this.projectsSidebarItem = page.locator('li:has-text("Projects")'); + this.draftsSidebarItem = page.locator('li:has-text("Drafts")'); + this.librariesSidebarItem = page.locator('li:has-text("Libraries")'); + this.pinnedProjectsSidebarItem = page.locator( + 'div[data-test="pinned-projects"]' + ); + this.searchInput = page.locator('#search-input'); this.projectOptions = page.locator('[data-test="project-options"]'); + + // Import files this.fileImport = page.locator('[data-test="file-import"]'); this.modal = page.locator('#modal'); this.modalCloseButton = page.locator('.modal-close-button'); this.modalTitle = page.locator('.modal-header-title h2'); this.modalCancelButton = page.locator('.modal-footer .action-buttons .cancel-button'); this.modalAcceptButton = page.locator('.modal-footer .action-buttons .accept-button'); - this.feedbackBanner = page.locator('.feedback-banner') - this.feedbackBannerMessage = page.locator('.feedback-banner .message') - this.projectsSidebarItem = page.locator('li:has-text("Projects")'); - this.draftsSidebarItem = page.locator('li:has-text("Drafts")'); - this.pinnedProjectsSidebarItem = page.locator( - 'div[data-test="pinned-projects"]' - ); - this.searchInput = page.locator("#search-input"); + this.feedbackBanner = page.locator('.feedback-banner'); + this.feedbackBannerMessage = page.locator('.feedback-banner .message'); + this.importErrorMessage = page.locator('div[class="error-message"]'); //Fonts this.fontsSidebarItem = page.locator('li:has-text("Fonts")'); @@ -121,11 +128,12 @@ exports.DashboardPage = class DashboardPage extends BasePage { ); this.saveFontButton = page.locator('button:has-text("Save")'); this.searchFontInput = page.locator("input[placeholder='Search font']"); + this.fontFormatError = page.locator("div[class='banner error fixed']"); + + //Teams this.teamSelector = page.locator(".current-team"); this.teamList = page.locator("ul[class*='teams-dropdown']"); this.createNewTeamMenuItem = page.locator("#teams-selector-create-team"); - - //Teams this.teamNameInput = page.locator("#name"); this.createNewTeamButton = page.locator("input[value='Create new team']"); this.teamMenuItem = page.locator(".current-team .team-name"); @@ -199,6 +207,7 @@ exports.DashboardPage = class DashboardPage extends BasePage { this.teamInfoSection = page.locator('div[class="block info-block"]'); this.continueButton = page.locator('input[value="Continue"]'); this.acceptButton = page.locator('input[value="Accept"]'); + this.noLibrariesPlacelder = page.locator('div[data-test="empty-placeholder"] p'); } async isHeaderDisplayed(title) { @@ -468,7 +477,7 @@ exports.DashboardPage = class DashboardPage extends BasePage { await this.duplicateProjectMenuItem.click(); } - async clickSidebarItem(item) { + async openSidebarItem(item) { switch (item) { case "Projects": await this.projectsSidebarItem.click(); @@ -479,7 +488,15 @@ exports.DashboardPage = class DashboardPage extends BasePage { case "Fonts": await this.fontsSidebarItem.click(); break; + case "Libraries": + await this.librariesSidebarItem.click(); + break; } + await expect(this.header).toHaveText(item); + } + + async checkNoLibrariesExist() { + await expect(this.noLibrariesPlacelder).toContainText("Files added to Libraries will appear here."); } async clickUnpinProjectButton() { @@ -510,6 +527,13 @@ exports.DashboardPage = class DashboardPage extends BasePage { await expect(this.uploadFontButton).not.toBeVisible(); } + async uploadFontWithInvalidFormat(filePath) { + const fontName = filePath.split('/')[1]; + const warning =`The font '${fontName}' could not be loaded`; + await this.uploadFontSelector.setInputFiles(filePath); + await expect(this.fontFormatError).toHaveText(warning); + } + async isFontUploaded(fontName, fontStyle) { await expect(this.fontNameTableCell).toHaveText(fontName); await expect(this.fontStyleTableCell).toHaveText(fontStyle); @@ -733,8 +757,7 @@ exports.DashboardPage = class DashboardPage extends BasePage { await this.acceptButton.click(); } - async importFile(file) { - await this.projectOptions.click(); + async importFileProcessingSuccess(file) { const fileChooserPromise = this.page.waitForEvent("filechooser"); await this.fileImport.click(); const fileChooser = await fileChooserPromise; @@ -742,11 +765,40 @@ exports.DashboardPage = class DashboardPage extends BasePage { await expect(this.modalTitle).toBeVisible(); await expect(this.modalTitle).toHaveText("Import Penpot files"); await this.modalAcceptButton.click(); - await this.feedbackBanner.waitFor('visible'); + await this.feedbackBanner.waitFor({ state: 'visible' }); await expect(this.feedbackBannerMessage).toHaveText("1 file has been imported successfully."); await this.modalAcceptButton.click(); } + async importFileProcessingError(file) { + const fileChooserPromise = this.page.waitForEvent("filechooser"); + await this.fileImport.click(); + const fileChooser = await fileChooserPromise; + await fileChooser.setFiles(file); + await expect(this.modalTitle).toBeVisible(); + await expect(this.modalTitle).toHaveText("Import Penpot files"); + await expect(this.modalAcceptButton).toBeVisible(); + await expect(this.modalAcceptButton).toBeDisabled(); + + await expect(this.importErrorMessage).toHaveText("Oops! We couldn't import this file"); + await this.modalCancelButton.click(); + } + + async importFile(file) { + await this.projectOptions.click(); + await this.importFileProcessingSuccess(file); + } + + async importFileFromProjectPage(file) { + await this.headerOptionsMenuButton.click(); + await this.importFileProcessingSuccess(file); + } + + async importFileWithInvalidFormat(file) { + await this.headerOptionsMenuButton.click(); + await this.importFileProcessingError(file); + } + async importAndOpenFile(file) { await this.importFile(file); await this.openFile(); diff --git a/pages/login-page.js b/pages/login-page.js index c6493ff..981d28b 100644 --- a/pages/login-page.js +++ b/pages/login-page.js @@ -6,6 +6,7 @@ exports.LoginPage = class LoginPage extends BasePage { */ constructor(page) { super(page); + this.pageTitle = page.locator('h1[data-test="login-title"]'); this.emailInput = page.locator("#email"); this.pwdInput = page.locator("#password"); this.loginButton = page.locator('input[name="submit"]'); @@ -17,6 +18,7 @@ exports.LoginPage = class LoginPage extends BasePage { ); this.section = page.locator('section[class="auth-content"]'); this.loginErrorBanner = page.locator('div[data-test="login-banner"]'); + this.createAccountLink = page.locator('a:has-text("Create an account")'); } async goto() { @@ -56,7 +58,7 @@ exports.LoginPage = class LoginPage extends BasePage { } async clickHeader() { - await this.header.click(); + await this.pageTitle.click(); } async isLoginErrorMessageDisplayed(message) { @@ -67,4 +69,8 @@ exports.LoginPage = class LoginPage extends BasePage { await expect(this.header).toBeVisible(); await expect(this.header).toHaveText(title); } + + async clickOnCreateAccount() { + await this.createAccountLink.click(); + } }; diff --git a/pages/main-page.js b/pages/main-page.js index bcccaa8..3fd27cb 100644 --- a/pages/main-page.js +++ b/pages/main-page.js @@ -572,6 +572,8 @@ exports.MainPage = class MainPage extends BasePage { //Header this.savedChangesIcon = page.locator('div[class="saved"]'); this.usersSection = page.locator('div[class="users-section"]'); + this.projectNameSpan = page.locator('div[class="project-tree"] span[class="project-name"]'); + this.fileNameSpan = page.locator('div[class="project-tree"] span') //History panel this.historyPanelButton = page.locator('button[class^="document-history"]'); @@ -733,6 +735,11 @@ exports.MainPage = class MainPage extends BasePage { await expect(this.pencilBoxButton).toBeVisible(); } + async isProjectAndFileNameExistInFile(projectName, fileName) { + await expect(this.projectNameSpan).toContainText(projectName); + await expect(this.fileNameSpan.last()).toHaveText(fileName); + } + async clickCanvasBackgroundColorIcon() { await this.canvasBackgroundColorIcon.click(); } diff --git a/pages/register-page.js b/pages/register-page.js new file mode 100644 index 0000000..9fd30db --- /dev/null +++ b/pages/register-page.js @@ -0,0 +1,62 @@ +const { BasePage } = require("./base-page"); +const { expect } = require("@playwright/test"); + +exports.RegisterPage = class RegisterPage extends BasePage { + /** + * @param {import('@playwright/test').Page} page + */ + constructor(page) { + super(page); + + this.pageTitle = page.locator('h1[data-test="registration-title"]'); + this.emailInput = page.locator('#email'); + this.passwordInput = page.locator('#password'); + this.createAccountBtn = page.locator('input[value="Create an account"]'); + this.emailInputError = page.locator('span[data-test="email-input-error"]'); + this.passwordInputError = page.locator('span[data-test="-error"]') + } + + async isRegisterPageOpened() { + await expect(this.pageTitle).toBeVisible(); + await expect(this.pageTitle).toHaveText('Create an account'); + } + + async enterEmail(email) { + await this.emailInput.fill(email); + } + + async enterPassword(password) { + await this.passwordInput.fill(password); + } + + async clickOnCreateAccount() { + await this.createAccountBtn.click(); + } + + async isCreateAccountBtnDisplayed() { + await expect(this.createAccountBtn).toBeVisible(); + } + + async isCreateAccountBtnDisabled() { + await expect(this.createAccountBtn).toBeDisabled(); + } + + async isEmailInputErrorDisplayed(error) { + await expect(this.emailInputError).toBeVisible; + await expect(this.emailInputError).toHaveText(error); + } + + async isPasswordInputErrorDisplayed(error) { + await expect(this.passwordInput).toBeVisible; + await expect(this.passwordInputError).toHaveText(error); + } + + async clickOnPasswordInput() { + await this.passwordInput.click(); + } + + async clickOnHeader() { + await this.pageTitle.click(); + } + +} diff --git a/tests/dashboard/dashboard-files.spec.js b/tests/dashboard/dashboard-files.spec.js index 632c992..69f444e 100644 --- a/tests/dashboard/dashboard-files.spec.js +++ b/tests/dashboard/dashboard-files.spec.js @@ -2,14 +2,22 @@ const { dashboardTest } = require("../../fixtures"); const { MainPage } = require("../../pages/main-page"); const { DashboardPage } = require("../../pages/dashboard-page"); -dashboardTest( - "DA-2 Create new file in Drafts via 'New file' placeholder", - async ({ page }) => { - const dashboardPage = new DashboardPage(page); - await dashboardPage.createFileViaPlaceholder(); - const mainPage = new MainPage(page); - await mainPage.clickPencilBoxButton(); - await dashboardPage.checkNumberOfFiles("1 file"); +dashboardTest("DA-1 Create new file in Drafts on title panel",async ({ page }) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.createFileViaTitlePanel(); + const mainPage = new MainPage(page); + await mainPage.isMainPageLoaded(); + await mainPage.isProjectAndFileNameExistInFile("Drafts", "New File 1"); + await mainPage.clickPencilBoxButton(); + await dashboardPage.checkNumberOfFiles("1 file"); +}); + +dashboardTest("DA-2 Create new file in Drafts via 'New file' placeholder", async ({ page }) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.createFileViaPlaceholder(); + const mainPage = new MainPage(page); + await mainPage.clickPencilBoxButton(); + await dashboardPage.checkNumberOfFiles("1 file"); } ); @@ -60,6 +68,24 @@ dashboardTest( } ); +dashboardTest("DA-11 Remove file as Shared Library via Options icon in Drafts", + async ({ page }) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.createFileViaPlaceholder(); + const mainPage = new MainPage(page); + await mainPage.isMainPageLoaded(); + await mainPage.clickPencilBoxButton(); + await dashboardPage.addFileAsSharedLibraryViaOptionsIcon(); + await dashboardPage.isSharedLibraryIconDisplayed(); + await dashboardPage.openSidebarItem("Libraries"); + await dashboardPage.isFileNameDisplayed("New File 1"); + await dashboardPage.openSidebarItem("Drafts"); + await dashboardPage.deleteFileAsSharedLibraryViaOptionsIcon(); + await dashboardPage.isSharedLibraryIconNotDisplayed(); + await dashboardPage.openSidebarItem("Libraries"); + await dashboardPage.checkNoLibrariesExist(); + }); + dashboardTest( "DA-12 Remove file as Shared Library in Drafts via rightclick", async ({ page }) => { @@ -96,6 +122,21 @@ dashboardTest( } ); +dashboardTest("DA-17 Import file to Drafts .penpot", async ({page}) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.openSidebarItem("Drafts"); + await dashboardPage.importFileFromProjectPage("documents/QA test file.penpot") + await dashboardPage.isFileNameDisplayed("Wireframing kit"); // issue is reported 5596 + } +); + +dashboardTest("DA-18 Import file to Drafts svgjson", async ({page}) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.openSidebarItem("Drafts"); + // await dashboardPage.importFileFromProjectPage("documents/QA test zip file.zip") + // await dashboardPage.isFileNameDisplayed("Wireframing kit"); // issue is reported 5597 +}); + dashboardTest( "DA-22 Delete file in Drafts via rightclick", async ({ page }) => { @@ -372,7 +413,7 @@ dashboardTest("DA-53 Duplicate Project", async ({ page }) => { await mainPage.clickPencilBoxButton(); await dashboardPage.duplicateProjectViaRightclick(); await dashboardPage.isHeaderDisplayed("TestProject (copy)"); - await dashboardPage.clickSidebarItem("Projects"); + await dashboardPage.openSidebarItem("Projects"); await dashboardPage.duplicateProjectViaOptionsIcon(); await dashboardPage.isHeaderDisplayed("TestProject (copy) (copy)"); }); @@ -402,6 +443,12 @@ dashboardTest("DA-55 Pin project", async ({ page }) => { await dashboardPage.checkPinnedProjectsSidebarItem("TestProject"); }); +dashboardTest("DA-59 Import file to project - fail invalid format", async ({ page }) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.openSidebarItem("Drafts"); + await dashboardPage.importFileWithInvalidFormat("images/images.png") +}); + dashboardTest("DA-60-1 Delete project via rightclick", async ({ page }) => { const dashboardPage = new DashboardPage(page); await dashboardPage.clickAddProjectButton(); @@ -432,7 +479,7 @@ dashboardTest("DA-62 Search file from Drafts", async ({ page }) => { const mainPage = new MainPage(page); await mainPage.clickPencilBoxButton(); await dashboardPage.renameFileViaRightclick("qwe"); - await dashboardPage.clickSidebarItem("Drafts"); + await dashboardPage.openSidebarItem("Drafts"); await dashboardPage.search("qwe"); await dashboardPage.isHeaderDisplayed("Search results"); await dashboardPage.isFileNameDisplayed("qwe"); @@ -447,7 +494,7 @@ dashboardTest("DA-63 Search file from Projects", async ({ page }) => { const mainPage = new MainPage(page); await mainPage.clickPencilBoxButton(); await dashboardPage.renameFileViaRightclick("qaz"); - await dashboardPage.clickSidebarItem("Projects"); + await dashboardPage.openSidebarItem("Projects"); await dashboardPage.search("qaz"); await dashboardPage.isHeaderDisplayed("Search results"); await dashboardPage.isFileNameDisplayed("qaz"); diff --git a/tests/dashboard/dashboard-fonts.spec.js b/tests/dashboard/dashboard-fonts.spec.js index cef48ba..d8b770f 100644 --- a/tests/dashboard/dashboard-fonts.spec.js +++ b/tests/dashboard/dashboard-fonts.spec.js @@ -4,20 +4,26 @@ const { test } = require("@playwright/test"); test.beforeEach(async ({ page }) => { const dashboardPage = new DashboardPage(page); - await dashboardPage.clickSidebarItem("Fonts"); + await dashboardPage.openSidebarItem("Fonts"); await dashboardPage.deleteFontsIfExist(); }); dashboardTest("DA-66 Upload single font", async ({ page }) => { const dashboardPage = new DashboardPage(page); - await dashboardPage.clickSidebarItem("Fonts"); + await dashboardPage.openSidebarItem("Fonts"); await dashboardPage.uploadFont("fonts/Pacifico.ttf"); await dashboardPage.isFontUploaded("Pacifico", "Regular"); }); +dashboardTest("DA-68 Fonts - upload fail invalid file format", async ({ page }) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.openSidebarItem("Fonts"); + await dashboardPage.uploadFontWithInvalidFormat("images/images.png"); +}); + dashboardTest("DA-69 Search font", async ({ page }) => { const dashboardPage = new DashboardPage(page); - await dashboardPage.clickSidebarItem("Fonts"); + await dashboardPage.openSidebarItem("Fonts"); await dashboardPage.uploadFont("fonts/ArialTh.ttf"); await dashboardPage.uploadFont("fonts/Allura-Regular.otf"); await dashboardPage.searchFont("Arial Th"); @@ -25,7 +31,7 @@ dashboardTest("DA-69 Search font", async ({ page }) => { dashboardTest("DA-71 Edit font", async ({ page }) => { const dashboardPage = new DashboardPage(page); - await dashboardPage.clickSidebarItem("Fonts"); + await dashboardPage.openSidebarItem("Fonts"); await dashboardPage.uploadFont("fonts/Allura-Regular.otf"); await dashboardPage.isFontUploaded("Allura", "Regular"); await dashboardPage.editFont("New Test Font"); @@ -33,7 +39,7 @@ dashboardTest("DA-71 Edit font", async ({ page }) => { dashboardTest("DA-72 Delete font", async ({ page }) => { const dashboardPage = new DashboardPage(page); - await dashboardPage.clickSidebarItem("Fonts"); + await dashboardPage.openSidebarItem("Fonts"); await dashboardPage.uploadFont("fonts/Pacifico.ttf"); await dashboardPage.isFontUploaded("Pacifico", "Regular"); await dashboardPage.deleteFont(); diff --git a/tests/signup.spec.js b/tests/signup.spec.js new file mode 100644 index 0000000..698e6b2 --- /dev/null +++ b/tests/signup.spec.js @@ -0,0 +1,45 @@ +const { test } = require("@playwright/test"); +const { LoginPage } = require("../pages/login-page") +const { RegisterPage } = require("../pages/register-page") + +test("ON-5 Sign up with invalid email address",async ({page}) => { + const loginPage = new LoginPage(page); + const registerPage = new RegisterPage(page); + await loginPage.goto(); + await loginPage.clickOnCreateAccount(); + await registerPage.isRegisterPageOpened(); + await registerPage.enterEmail('test.com'); + await registerPage.enterPassword(process.env.LOGIN_PWD); + await registerPage.isEmailInputErrorDisplayed('Enter a valid email please'); + await registerPage.isCreateAccountBtnDisplayed(); + await registerPage.isCreateAccountBtnDisabled(); +}); + +test("ON-6 Sign up with no password", async ({page}) => { + const loginPage = new LoginPage(page); + const registerPage = new RegisterPage(page); + await loginPage.goto(); + await loginPage.clickOnCreateAccount(); + await registerPage.isRegisterPageOpened(); + await registerPage.enterEmail(process.env.LOGIN_EMAIL); + await registerPage.clickOnPasswordInput(); + await registerPage.clickOnHeader(); + await registerPage.isPasswordInputErrorDisplayed('Password should at least be 8 characters') + await registerPage.isCreateAccountBtnDisplayed(); + await registerPage.isCreateAccountBtnDisabled(); +}); + +test("ON-7 Sign up with incorrect password", async ({page}) => { + const loginPage = new LoginPage(page); + const registerPage = new RegisterPage(page); + await loginPage.goto(); + await loginPage.clickOnCreateAccount(); + await registerPage.isRegisterPageOpened(); + await registerPage.enterEmail(process.env.LOGIN_EMAIL); + await registerPage.enterPassword('1234'); + await registerPage.isPasswordInputErrorDisplayed('Password should at least be 8 characters') + await registerPage.isCreateAccountBtnDisplayed(); + await registerPage.isCreateAccountBtnDisabled(); +}); + +