Skip to content

Commit

Permalink
refactor: refactor locators, update snapshots (win32, chrome/firefox)
Browse files Browse the repository at this point in the history
  • Loading branch information
chalapkoStanislav committed Oct 21, 2024
1 parent 5233926 commit ab44b90
Show file tree
Hide file tree
Showing 54 changed files with 263 additions and 328 deletions.
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Prerequisites for local run:
- `LOGIN_EMAIL` (email from your Penpot account)
- `LOGIN_PWD` (password from your Penpot account)
- `BASE_URL` (Penpot url - e.g. http://localhost:9001/ if deployed locally)
- `GMAIL_NAME` (Gmail account name for email verification)
- `REFRESH_TOKEN` (Token for email access)
- `CLIENT_ID` (for email access)
- `CLIENT_SECRET` (for email access)

**2. Test run - main notes.**

Expand Down Expand Up @@ -56,16 +60,15 @@ Some settings from _playwright.config.js_ may be useful:

- All tests should be independent for running them in parallel mode
- For run tests in parallel mode need to update key `workers` in `playwright.config.js` file
- `workers`: `process.env.CI ? 2 : 2` - by default 2 workers are used for local run and run on CI/CD.
- `workers`: `process.env.CI ? 3 : 3` - by default 3 workers are used for local run and run on CI/CD.
- For disabling parallelism set `workers` to 1.

**5. Tests amount and execution time.**

- For now there are 327 tests in current repository
- If parallel execution is enabled with default amount of workers (2) the average time for each browser is the following:
- Chrome: 43 mins
- Firefox: 45 mins
- Webkit: 55 mins
- For now there are 531 tests in current repository
- If parallel execution is enabled with default amount of workers (3) the average time for each browser is the following:
- Chrome: 72 mins
- Firefox: 81 mins

**6. Snapshots comparison.**

Expand Down Expand Up @@ -97,7 +100,6 @@ To exclude performance tests from the periodical regression test run the followi

- for Chrome: `"npx playwright test --project=chrome -gv 'PERF'"`
- for Firefox: `"npx playwright test --project=firefox -gv 'PERF'"`
- for Webkit: `"npx playwright test --project=webkit -gv 'PERF'"`

Note: The above scripts should be executed via the command line. Do not run them directly from the _package.json_,
because in such way performance tests are not ignored.
Expand All @@ -110,6 +112,10 @@ For each environment the appropriate secrets were added:
- _LOGIN_EMAIL_ (email from your Penpot account, which is used for tests)
- _LOGIN_PWD_ (password from your Penpot account, which is used for tests)
- _BASE_URL_ (Penpot url)
- _GMAIL_NAME_ (Gmail account name for email verification)
- _REFRESH_TOKEN_ (Token for email access)
- _CLIENT_ID_ (for email access)
- _CLIENT_SECRET_ (for email access)

2 _.yml_ files were added into _.github/workflows_ directory with settings for environments:

Expand Down
4 changes: 2 additions & 2 deletions pages/dashboard/dashboard-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ exports.DashboardPage = class DashboardPage extends BasePage {
this.pinUnpinProjectButton = page.getByRole('button', { name: 'Pin/Unpin' });
this.projectOptionsMenuButton = page.getByTestId('project-options');
this.projectsSidebarItem = page.getByRole('listitem').filter({ hasText: 'Projects' });
this.draftsSidebarItem = page.getByTestId('drafts-link-sidebar');
this.librariesSidebarItem = page.getByTestId('libs-link-sidebar');
this.draftsSidebarItem = page.getByRole('listitem').filter({ hasText: 'Drafts' });
this.librariesSidebarItem = page.getByRole('listitem').filter({ hasText: 'Libraries' });
this.pinnedProjectsSidebarItem = page.getByTestId('pinned-projects');
this.searchInput = page.locator('#search-input');
this.projectOptions = page.getByTestId('project-options');
Expand Down
68 changes: 26 additions & 42 deletions pages/dashboard/team-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ exports.TeamPage = class TeamPage extends BasePage {
'button[class*="current-team"] div[class*="team-name"]',
);
this.teamNameLabel = page.locator('//div[text()="Team info"]/following-sibling::div[1]');
this.teamOptionsMenuButton = page.locator('button[class*="switch-options"]');
this.deleteTeamMenuItem = page.locator('#teams-options-delete-team');
this.deleteTeamButton = page.locator('input[value="Delete team"]');
this.teamSettingsMenuItem = page.locator('li[data-testid="team-settings"]');
this.renameTeamMenuItem = page.locator('li[data-testid="rename-team"]');
this.uploadTeamImageButton = page.locator('input[type="file"]');
this.updateTeamButton = page.locator('button:has-text("Update team")');
this.teamOptionsMenuButton = page.getByRole('button', { name: 'team-management' });
this.deleteTeamMenuItem = page.getByRole('menuitem', { name: 'Delete team' });
this.deleteTeamButton = page.getByRole('button', { name: 'Delete team' });
this.teamSettingsMenuItem = page.getByRole('menuitem', { name: 'Settings' });
this.renameTeamMenuItem = page.getByRole('menuitem', { name: 'Rename' });
this.uploadTeamImageButton = page.getByLabel('uploader');
this.updateTeamButton = page.getByRole('button', { name: 'Update team' });
this.teamOwnerSpan = page.locator(
`//*[contains(@class,'owner-icon')]/../span`,
);
Expand All @@ -42,31 +42,27 @@ exports.TeamPage = class TeamPage extends BasePage {
this.teamOwnerSection = page.locator('//div[text()="Team members"]/..');
this.teamStatsSection = page.locator('//div[text()="Team projects"]/..');

this.membersMenuItem = page.locator('li[data-testid="team-members"]');
this.membersMenuItem = page.getByRole('menuitem', { name: 'Members' });

//Invitations
this.invitationsMenuItem = page.locator('li[data-testid="team-invitations"]');
this.inviteMembersToTeamButton = page.locator('a[data-testid="invite-member"]');
this.invitationsMenuItem = page.getByRole('menuitem', { name: 'Invitations' });
this.inviteMembersToTeamButton = page.getByTestId('invite-member');
this.inviteMembersPopUpHeader = page.locator(
'div[class*="modal-team-container"] div[class*="title"]',
);
this.inviteMembersTeamHeroButton = page.locator(
'button:has-text("Invite members")',
);
this.inviteMembersTeamHeroButton = page.getByRole('button', { name: 'Invite members' });
this.inviteMembersToTeamRoleSelectorButton = page.locator(
'div[class*="custom-select"]',
);
this.adminRoleSelector = page.locator('li:has-text("Admin")');
this.editorRoleSelector = page.locator('li:has-text("Editor")');
this.ownerRoleSelector = page.locator('li:has-text("Owner")');
this.transferOwnershipButton = page.locator('input[value="Transfer ownership"]');
this.leaveTeamButton = page.locator('input[value="Leave team"]');
this.ownerLeaveTeamButton = page.locator('input[value="Promote and leave"]');
this.deleteMemberButton = page.locator('input[value="Delete member"]');
this.inviteMembersToTeamEmailInput = page.locator(
'input[placeholder="Emails, comma separated"]',
);
this.sendInvitationButton = page.locator('button:has-text("Send invitation")');
this.adminRoleSelector = page.getByRole('listitem').filter({ hasText: 'Admin' });
this.editorRoleSelector = page.getByRole('listitem').filter({ hasText: 'Editor' });
this.ownerRoleSelector = page.getByRole('listitem').filter({ hasText: 'Owner' });
this.transferOwnershipButton = page.getByRole('button', { name: 'Transfer ownership' });
this.leaveTeamButton = page.getByRole('button', { name: 'Leave team' });
this.ownerLeaveTeamButton = page.getByRole('button', { name: 'Promote and leave' });
this.deleteMemberButton = page.getByRole('button', { name: 'Delete member' });
this.inviteMembersToTeamEmailInput = page.getByPlaceholder('Emails, comma separated');
this.sendInvitationButton = page.getByRole('button', { name: 'Send invitation' });
this.invitationRecord = page.locator(
'div[class*="table-rows"] div[class*="table-row"]',
);
Expand All @@ -83,18 +79,10 @@ exports.TeamPage = class TeamPage extends BasePage {
this.invitationRecordOptionsMenuButton = page.locator(
'div[class*="main_ui_dashboard_team__table-field"] button',
);
this.invitationRecordResendInvititationMenuItem = page.locator(
'li:has-text("Resend invitation")',
);
this.invitationRecordDeleteInvititationMenuItem = page.locator(
'li:has-text("Delete invitation")',
);
this.memberRecordleaveTeamMenuItem = page.locator(
'li:has-text("Leave team")',
);
this.memberRecordDeleteMemberMenuItem = page.locator(
'li:has-text("Remove member")',
);
this.invitationRecordResendInvititationMenuItem = page.getByRole('listitem').filter({ hasText: 'Resend invitation' });
this.invitationRecordDeleteInvititationMenuItem = page.getByRole('listitem').filter({ hasText: 'Delete invitation' });
this.memberRecordleaveTeamMenuItem = page.getByRole('listitem').filter({ hasText: 'Leave team' });
this.memberRecordDeleteMemberMenuItem = page.getByRole('listitem').filter({ hasText: 'Remove member' });
this.invitationWarningSpan = page.locator(
'aside[class*="warning"] div[class*="context_notification"]',
);
Expand Down Expand Up @@ -139,18 +127,14 @@ exports.TeamPage = class TeamPage extends BasePage {

async switchTeam(teamName) {
await this.openTeamsListIfClosed();
const teamOption = this.page.locator(
`li[class*="team-dropdown-item"] span[class*="team-text"]:text-is("${teamName}")`,
);
const teamOption = this.page.getByRole('menuitem').filter({ hasText: teamName });
await teamOption.click();
await this.isTeamSelected(teamName);
}

async deleteTeam(teamName) {
await this.openTeamsListIfClosed();
const teamSel = this.page.locator(
`ul[class*="teams-dropdown"] li[role="menuitem"] span[title="${teamName}"]`,
);
const teamSel = this.page.getByRole('menuitem').filter({ hasText: teamName });
if (await teamSel.isVisible()) {
await teamSel.click();
await this.isTeamSelected(teamName);
Expand Down
2 changes: 1 addition & 1 deletion pages/forgot-password-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ exports.ForgotPasswordPage = class ForgotPasswordPage extends BasePage {
constructor(page) {
super(page);

this.emailInput = page.locator('#email');
this.emailInput = page.getByRole('textbox', { name: 'Work email' });
this.recoverPasswordButton = page.getByTestId('recovery-resquest-submit');
this.recoveryPwdInput = page.locator('#password-1');
this.recoveryPwdConfirmInput = page.locator('#password-2');
Expand Down
2 changes: 1 addition & 1 deletion pages/profile-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ exports.ProfilePage = class ProfilePage extends BasePage {
}

async isPasswordInputErrorDisplayed(error) {
await expect(this.passwordInputError).toHaveText(error);
await expect(this.passwordInputError.first()).toHaveText(error);
}

async isChangePasswordButtonDisabled() {
Expand Down
58 changes: 24 additions & 34 deletions pages/workspace/assets-panel-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,21 @@ exports.AssetsPanelPage = class AssetsPanelPage extends BasePage {
'div[class*="components_title_bar"] span:text-is("Components")',
);
this.assetsPanel = page.locator('article[class*="assets-bar"]');
this.assetsSectionName = page.locator(
'span[class*="assets_common__section-name"]',
);
this.assetsSectionName = page.getByTestId('left-sidebar');
this.assetsSectionNumbers = page.locator(
'span[class*="assets_common__num-assets"]',
);
this.renameFileLibraryMenuItem = page.locator('li:has-text("Rename")');
this.deleteFileLibraryMenuItem = page.locator('li:has-text("Delete")');
this.editFileLibraryMenuItem = page.locator('li:has-text("Edit")');
this.createGroupFileLibraryMenuItem = page.locator('li:has-text("Group")');
this.ungroupFileLibraryMenuItem = page.locator('li:has-text("Ungroup")');
this.groupNameInput = page.locator('#name');
this.createGroupButton = page.locator('input[value="Create"]');
this.renameGroupButton = page.locator('input[value="Rename"]');
this.renameFileLibraryMenuItem = page.getByRole('menuitem').filter({ hasText: 'Rename' });
this.deleteFileLibraryMenuItem = page.getByRole('menuitem').filter({ hasText: 'Delete' });
this.editFileLibraryMenuItem = page.getByRole('menuitem').filter({ hasText: 'Edit' });
this.createGroupFileLibraryMenuItem = page.getByRole('menuitem').filter({ hasText: 'Group' });
this.ungroupFileLibraryMenuItem = page.getByRole('menuitem').filter({ hasText: 'Ungroup' });
this.groupNameInput = page.getByRole('textbox', { name: 'Group name' });
this.createGroupButton = page.getByRole('button', { name: 'Create' });
this.renameGroupButton = page.getByRole('button', { name: 'Rename' });
this.fileLibraryGroupTitle = page.locator('div[class*="group-title"]');
this.fileLibraryListViewButton = page.locator('label[for="opt-list"] span');
this.fileLibraryGridViewButton = page.locator('label[for="opt-grid"] span');
this.fileLibraryListViewButton = page.getByTitle('List view');
this.fileLibraryGridViewButton = page.getByTitle('Grid view');
this.addFileLibraryColorButton = page.locator(
'button[class*="assets_colors__assets-btn"]',
);
Expand All @@ -63,26 +61,20 @@ exports.AssetsPanelPage = class AssetsPanelPage extends BasePage {
'div[class*="typography-entry"]',
);
this.fontSelector = page.locator('div[class*="typography__font-option"]');
this.fontSelectorSearchInput = page.locator('input[placeholder="Search font"]');
this.fontSelectorSearchInput = page.getByRole('textbox', { name: 'Search font' });
this.fontSizeInput = page.locator('div[class*="font-size-select"] input');
this.typographyNameInput = page.locator('input[class*="adv-typography-name"]');
this.assetsTitleText = page.locator(
'div[class*="asset-section"] span[class*="title-name"]',
);
this.assetsTypeButton = page.locator(
'div[class*="assets-header"] button[class*="section-button"]',
);
this.assetsTypeButton = page.getByRole('button', { name: 'Filter' });
this.assetsTypeDropdown = page.locator('ul[class*="context-menu-items"]');
this.assetsTypeAll = page.locator('#section-all');
this.assetsTypeComponents = page.locator('#section-components');
this.assetsTypeColors = page.locator('#section-color');
this.assetsTypeTypographies = page.locator('#section-typography');
this.duplicateMainComponentMenuItem = page.locator(
'li:has-text("Duplicate main")',
);
this.showMainComponentMenuItem = page.locator(
'li:has-text("Show main component")',
);
this.duplicateMainComponentMenuItem = page.getByRole('menuitem').filter({ hasText: 'Duplicate main' });
this.showMainComponentMenuItem = page.getByRole('menuitem').filter({ hasText: 'Show main component' });
this.fileLibraryComponentNameInput = page.locator(
'div[class*="assets_components__editing"] input',
);
Expand All @@ -91,24 +83,22 @@ exports.AssetsPanelPage = class AssetsPanelPage extends BasePage {
);

//Assets panel - Libraries
this.addAsSharedLibraryButton = page.locator(
'input[value="Add as Shared Library"]',
);
this.removeAsSharedLibraryButton = page.locator('input[value="Unpublish"]');
this.addAsSharedLibraryButton = page.getByRole('button', { name: 'Add as Shared Library' });
this.removeAsSharedLibraryButton = page.getByRole('button', { name: 'Unpublish' });
this.sharedLibraryBadge = page.locator('span[class*="shared-badge"]');
this.librariesOpenModalButton = page.locator('button[class*="libraries-button"]');
this.addSharedLibraryButton = page.locator('input[value="Publish"]');
this.cancelSharedLibraryButton = page.locator('input[value="Cancel"]');
this.searchSharedLibrariesInput = page.locator('input[placeholder="Search shared libraries"]');
this.librariesOpenModalButton = page.getByRole('button', { name: 'Libraries' });
this.addSharedLibraryButton = page.getByRole('button', { name: 'Publish' });
this.cancelSharedLibraryButton = page.getByRole('button', { name: 'Cancel' });
this.searchSharedLibrariesInput = page.getByRole('textbox', { name: 'Search shared libraries' });
this.searchSharedLibrariesClearButton = page.locator('button[class*="search_bar__clear"]');
this.libraryTitle = page.locator('div[class*="special-title"]');
this.libraryComponentsTitle = page.locator(
'//*[@class="icon-component"]/../../../../../button/div/span'
);
this.dismissButton = page.locator('button:text-is("Dismiss")');
this.dismissButton = page.getByRole('button', { name: 'Dismiss' });
this.librariesUpdatesTab = page.getByRole('tab', { name: 'UPDATES' });
this.librariesUpdateButton = page.getByRole('button', { name: 'Update' });
this.librariesMoreInfoButton = page.locator('input[value="More info"]');
this.librariesMoreInfoButton = page.getByRole('button', { name: 'More info' });
this.closeModalButton = page.locator('svg[class*="close-icon"]');
this.librariesModal = page.locator('div[class*="libraries__modal-dialog"]');
}
Expand All @@ -131,7 +121,7 @@ exports.AssetsPanelPage = class AssetsPanelPage extends BasePage {
}

async isAssetsSectionNameDisplayed(name, amount) {
await expect(this.assetsSectionName).toHaveText(name);
await expect(this.assetsSectionName.getByText(name)).toHaveText(name);
await expect(this.assetsSectionNumbers).toHaveText(amount);
}

Expand Down
10 changes: 5 additions & 5 deletions pages/workspace/color-palette-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ exports.ColorPalettePage = class ColorPalettePage extends BasePage {
this.popUp = page.locator('div[class*="colorpicker-tooltip"]');
this.hexInput = page.locator('#hex-value');
this.modalHexInput = page.locator('div[class*="selected-color-group"] span[class*="color-input-wrapper"] input');
this.saveColorStyleButton = page.locator('button:has-text("Save color style")');
this.saveColorStyleButton = page.getByRole('button', { name: 'Save color style' });
this.colorsLibrariesSelect = page.locator(
'div[class*="colorpicker_libraries__select-wrapper"]',
);
this.colorsFileLibraryOptions = page.locator('span:has-text("File library")');
this.colorsFileLibraryOptions = page.getByText('File library');
this.colorPaletteActionsBtn = page.locator('button[class*="palette-actions"]');
this.colorPaletteMenu = page.locator('ul[class*="palette-menu"]');
this.colorPaletteFileLibraryOpt = page.locator('li:has-text("File library")');
this.colorPaletteRecentColorsOpt = page.locator('li:has-text("Recent colors")');
this.colorPaletteFileLibraryOpt = page.getByRole('listitem').filter({ hasText: 'File library' });
this.colorPaletteRecentColorsOpt = page.getByRole('listitem').filter({ hasText: 'Recent colors' });
}

async setHex(value) {
Expand Down Expand Up @@ -69,7 +69,7 @@ exports.ColorPalettePage = class ColorPalettePage extends BasePage {
}

async selectColorPaletteMenuOption(value) {
const menuSel = this.page.locator(`li:has-text("${value}")`);
const menuSel = this.page.getByRole('listitem').filter({ hasText: value });
await menuSel.click();
await expect(this.colorPaletteMenu).not.toBeVisible();
}
Expand Down
Loading

0 comments on commit ab44b90

Please sign in to comment.