0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-17 10:11:22 -05:00

Add visual testing to dashboard

This commit is contained in:
Eva Marco 2024-05-28 10:29:52 +02:00
parent 4e6c1857dd
commit 4e770fd326
26 changed files with 976 additions and 11 deletions

2
frontend/.gitignore vendored
View file

@ -10,3 +10,5 @@ node_modules/
/playwright-report/
/blob-report/
/playwright/.cache/
visual-dashboard.spec.js-snapshots

View file

@ -0,0 +1,8 @@
{
"~:id": "~u62edaeb8-e212-81ca-8004-80a6f8a42e8e",
"~:profile-id": "~uc7ce0794-0992-8105-8004-38e630f29a9b",
"~:created-at": "~m1718348381840",
"~:updated-at": "~m1718348381840",
"~:name": "new token",
"~:token": "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIn0.9aFN5YdOI-b-NQPos5uqF8J8b9iMyeri3yYhV5FlHuhNbRwk0YuftA.Dygx9O5-KsAHpuqD.ryTDCqelYOk1XYflTlDGFlzG8VLuElKHSGHdJyJvWqcCUANWzl8cVvezvU2GWg1Piin21KNrcV0TEcHPpDggySRbTn01MOIjw3vTVHdGrlHaVq5VpnWb5hCfs_P9kF7Y2IWOa4da4mM.IulvBQUllnay7clORd-NSg"
}

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,8 @@
[
{
"~:id": "~u62edaeb8-e212-81ca-8004-80a6f8a42e8e",
"~:name": "new token",
"~:created-at": "~m1718348381840",
"~:updated-at": "~m1718348381840"
}
]

View file

@ -0,0 +1,15 @@
[
{
"~:font-style": "normal",
"~:team-id": "~uc7ce0794-0992-8105-8004-38e630f40f6d",
"~:font-id": "~u838cda51-c50f-8032-8004-6ac92ea6eaea",
"~:font-weight": 400,
"~:ttf-file-id": "~ue3710e43-7e40-405d-a4ea-8bb85443d44b",
"~:modified-at": "~m1716880956479",
"~:otf-file-id": "~u72bd3cda-478a-4e0e-a372-4a4f7cdc1371",
"~:id": "~u28f4b65f-3667-8087-8004-6ac93050433a",
"~:woff1-file-id": "~ua4c0a056-2eb6-47cc-bf80-3115d14e048d",
"~:created-at": "~m1716880956479",
"~:font-family": "Milligram Variable Trial"
}
]

View file

@ -0,0 +1,19 @@
[{
"~:id": "~ue5a24d1b-ef1e-812f-8004-52bab84be6f7",
"~:team-id": "~uc7ce0794-0992-8105-8004-38e630f40f6d",
"~:created-at": "~m1715266551088",
"~:modified-at": "~m1715266551088",
"~:is-default": false,
"~:name": "New Project 1",
"~:is-pinned": false,
"~:count": 1
},
{
"~:id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
"~:team-id": "~uc7ce0794-0992-8105-8004-38e630f40f6d",
"~:created-at": "~m1713533116382",
"~:modified-at": "~m1713873823633",
"~:is-default": true,
"~:name": "Drafts",
"~:count": 1
}]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,219 @@
{
"~#set": [
{
"~:name": "New File 3",
"~:revn": 1,
"~:id": "~u28f4b65f-3667-8087-8004-69eca173cc07",
"~:is-shared": true,
"~:project-id": "~ue5a24d1b-ef1e-812f-8004-52bab84be6f7",
"~:created-at": "~m1713518796912",
"~:modified-at": "~m1713519762931",
"~:library-summary": {
"~:components": {
"~:count": 1,
"~:sample": [
{
"~:id": "~ua30724ae-f8d8-8003-8004-69ecacfc8a4c",
"~:name": "Rectangle",
"~:path": "",
"~:modified-at": "~m1716823150739",
"~:main-instance-id": "~ua30724ae-f8d8-8003-8004-69ecacfa2045",
"~:main-instance-page": "~u28f4b65f-3667-8087-8004-69eca173cc08",
"~:objects": {
"~ua30724ae-f8d8-8003-8004-69ecacfa2045": {
"~#shape": {
"~:y": 168,
"~:hide-fill-on-export": false,
"~:transform": {
"~#matrix": {
"~:a": 1.0,
"~:b": 0.0,
"~:c": 0.0,
"~:d": 1.0,
"~:e": 0.0,
"~:f": 0.0
}
},
"~:rotation": 0,
"~:hide-in-viewer": true,
"~:name": "Rectangle",
"~:width": 553,
"~:type": "~:frame",
"~:points": [
{
"~#point": {
"~:x": 481,
"~:y": 168
}
},
{
"~#point": {
"~:x": 1034,
"~:y": 168
}
},
{
"~#point": {
"~:x": 1034,
"~:y": 550
}
},
{
"~#point": {
"~:x": 481,
"~:y": 550
}
}
],
"~:component-root": true,
"~:show-content": true,
"~:proportion-lock": false,
"~:transform-inverse": {
"~#matrix": {
"~:a": 1.0,
"~:b": 0.0,
"~:c": 0.0,
"~:d": 1.0,
"~:e": 0.0,
"~:f": 0.0
}
},
"~:id": "~ua30724ae-f8d8-8003-8004-69ecacfa2045",
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
"~:component-id": "~ua30724ae-f8d8-8003-8004-69ecacfc8a4c",
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
"~:strokes": [],
"~:x": 481,
"~:main-instance": true,
"~:proportion": 1,
"~:selrect": {
"~#rect": {
"~:x": 481,
"~:y": 168,
"~:width": 553,
"~:height": 382,
"~:x1": 481,
"~:y1": 168,
"~:x2": 1034,
"~:y2": 550
}
},
"~:fills": [],
"~:flip-x": null,
"~:height": 382,
"~:component-file": "~u28f4b65f-3667-8087-8004-69eca173cc07",
"~:flip-y": null,
"~:shapes": [
"~ua30724ae-f8d8-8003-8004-69eca9b27c8c"
]
}
},
"~ua30724ae-f8d8-8003-8004-69eca9b27c8c": {
"~#shape": {
"~:y": 168,
"~:rx": 0,
"~:transform": {
"~#matrix": {
"~:a": 1.0,
"~:b": 0.0,
"~:c": 0.0,
"~:d": 1.0,
"~:e": 0.0,
"~:f": 0.0
}
},
"~:rotation": 0,
"~:grow-type": "~:fixed",
"~:hide-in-viewer": false,
"~:name": "Rectangle",
"~:width": 553,
"~:type": "~:rect",
"~:points": [
{
"~#point": {
"~:x": 481,
"~:y": 168
}
},
{
"~#point": {
"~:x": 1034,
"~:y": 168
}
},
{
"~#point": {
"~:x": 1034,
"~:y": 550
}
},
{
"~#point": {
"~:x": 481,
"~:y": 550
}
}
],
"~:proportion-lock": false,
"~:transform-inverse": {
"~#matrix": {
"~:a": 1.0,
"~:b": 0.0,
"~:c": 0.0,
"~:d": 1.0,
"~:e": 0.0,
"~:f": 0.0
}
},
"~:constraints-v": "~:scale",
"~:constraints-h": "~:scale",
"~:id": "~ua30724ae-f8d8-8003-8004-69eca9b27c8c",
"~:parent-id": "~ua30724ae-f8d8-8003-8004-69ecacfa2045",
"~:frame-id": "~ua30724ae-f8d8-8003-8004-69ecacfa2045",
"~:strokes": [],
"~:x": 481,
"~:proportion": 1,
"~:selrect": {
"~#rect": {
"~:x": 481,
"~:y": 168,
"~:width": 553,
"~:height": 382,
"~:x1": 481,
"~:y1": 168,
"~:x2": 1034,
"~:y2": 550
}
},
"~:fills": [
{
"~:fill-color": "#B1B2B5",
"~:fill-opacity": 1
}
],
"~:flip-x": null,
"~:ry": 0,
"~:height": 382,
"~:flip-y": null
}
}
}
}
]
},
"~:media": {
"~:count": 0,
"~:sample": []
},
"~:colors": {
"~:count": 0,
"~:sample": []
},
"~:typographies": {
"~:count": 0,
"~:sample": []
}
}
}
]
}

View file

@ -0,0 +1,6 @@
[
{ "~:email": "test1@mail.com", "~:role": "~:editor", "~:expired": true },
{ "~:email": "test2@mail.com", "~:role": "~:editor", "~:expired": false },
{ "~:email": "test3@mail.com", "~:role": "~:admin", "~:expired": true },
{ "~:email": "test4@mail.com", "~:role": "~:admin", "~:expired": false }
]

View file

@ -0,0 +1,16 @@
[
{
"~:is-admin": true,
"~:email": "foo@example.com",
"~:team-id": "~udd33ff88-f4e5-8033-8003-8096cc07bdf3",
"~:name": "Princesa Leia",
"~:fullname": "Princesa Leia",
"~:is-owner": false,
"~:modified-at": "~m1713533116365",
"~:can-edit": true,
"~:is-active": true,
"~:id": "~uc7ce0794-0992-8105-8004-38e630f29a9b",
"~:profile-id": "~uf56647eb-19a7-8115-8003-b6bc939ecd1b",
"~:created-at": "~m1713533116365"
}
]

View file

@ -0,0 +1,29 @@
[
{
"~:id": "~u8b479b80-e02d-8074-8004-4088dc6bfd11",
"~:project-id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
"~:created-at": "~m1714045521389",
"~:modified-at": "~m1714045654874",
"~:name": "New File 2",
"~:revn": 1,
"~:is-shared": false
},
{
"~:id": "~u95d6fdd8-48d8-8148-8004-38af910d2dbe",
"~:project-id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
"~:created-at": "~m1713518796912",
"~:modified-at": "~m1713519762931",
"~:name": "New File 1",
"~:revn": 1,
"~:is-shared": false
},
{
"~:id": "~u28f4b65f-3667-8087-8004-69eca173cc07",
"~:project-id": "~ue5a24d1b-ef1e-812f-8004-52bab84be6f7",
"~:created-at": "~m1713518796912",
"~:modified-at": "~m1713519762931",
"~:name": "New File 3",
"~:revn": 1,
"~:is-shared": true
}
]

View file

@ -0,0 +1 @@
{"~:projects":1,"~:files":3}

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,20 @@
[
{
"~:id": "~u29ce7ec9-e75d-81b4-8004-08100373558a",
"~:uri": {
"~#uri": "https://www.abc.es"
},
"~:mtype": "application/json",
"~:is-active": false,
"~:error-count": 0
},
{
"~:id": "~u43d6b3b1-40f7-807b-8003-f9846292b4c7",
"~:uri": {
"~#uri": "https://www.google.com"
},
"~:mtype": "application/json",
"~:is-active": true,
"~:error-count": 0
}
]

View file

@ -0,0 +1,29 @@
[
{
"~:id": "~u8b479b80-e02d-8074-8004-4088dc6bfd11",
"~:project-id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
"~:created-at": "~m1714045521389",
"~:modified-at": "~m1714045654874",
"~:name": "New File 2",
"~:revn": 1,
"~:is-shared": false
},
{
"~:id": "~u95d6fdd8-48d8-8148-8004-38af910d2dbe",
"~:project-id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
"~:created-at": "~m1713518796912",
"~:modified-at": "~m1713519762931",
"~:name": "New File 1",
"~:revn": 1,
"~:is-shared": false
},
{
"~:id": "~u28f4b65f-3667-8087-8004-69eca173cc07",
"~:project-id": "~ue5a24d1b-ef1e-812f-8004-52bab84be6f7",
"~:created-at": "~m1713518796912",
"~:modified-at": "~m1713519762931",
"~:name": "New File 3",
"~:revn": 1,
"~:is-shared": true
}
]

View file

@ -0,0 +1,48 @@
[
{
"~:features": {
"~#set": [
"layout/grid",
"styles/v2",
"fdata/pointer-map",
"fdata/objects-map",
"components/v2",
"fdata/shape-data-type"
]
},
"~:permissions": {
"~:type": "~:membership",
"~:is-owner": true,
"~:is-admin": true,
"~:can-edit": true
},
"~:name": "Default",
"~:modified-at": "~m1713533116375",
"~:id": "~uc7ce0794-0992-8105-8004-38e630f40f6d",
"~:created-at": "~m1713533116375",
"~:is-default": true
},
{
"~:features": {
"~#set": [
"layout/grid",
"styles/v2",
"fdata/pointer-map",
"fdata/objects-map",
"components/v2",
"fdata/shape-data-type"
]
},
"~:permissions": {
"~:type": "~:membership",
"~:is-owner": true,
"~:is-admin": true,
"~:can-edit": true
},
"~:name": "Second team",
"~:modified-at": "~m1701164272671",
"~:id": "~udd33ff88-f4e5-8033-8003-8096cc07bdf3",
"~:created-at": "~m1701164272671",
"~:is-default": false
}
]

View file

@ -50,6 +50,8 @@ export class DashboardPage extends BaseWebSocketPage {
static anyTeamId = "c7ce0794-0992-8105-8004-38e630f40f6d";
static secondTeamId = "dd33ff88-f4e5-8033-8003-8096cc07bdf3";
static draftProjectId = "c7ce0794-0992-8105-8004-38e630f7920b";
constructor(page) {
@ -60,12 +62,34 @@ export class DashboardPage extends BaseWebSocketPage {
this.draftTitle = page.getByRole("heading", { name: "Drafts" });
this.draftLink = page.getByTestId("drafts-link-sidebar");
this.draftsFile = page.getByText(/New File 1/);
this.fontsLink = page.getByTestId("fonts-link-sidebar");
this.fontsTitle = page.getByRole("heading", { name: "Fonts", level: 1 });
this.libsLink = page.getByTestId("libs-link-sidebar");
this.libsTitle = page.getByRole("heading", { name: "Libraries", level: 1 });
this.searchButton = page.getByRole("button", { name: "dashboard-search" });
this.searchTitle = page.getByRole("heading", { name: "Search results" });
this.searchInput = page.getByPlaceholder('Search…');
this.newFileName = page.getByText("New File 3");
this.teamDropdown = page.getByRole('button', { name: 'Your Penpot' });
this.userAccount = page.getByRole('button', { name: "Princesa Leia Princesa Leia" });
this.userProfileOption = page.getByText("Your account");
this.userAccountTitle = page.getByRole("heading", {name: "Your account"});
}
async setupDraftsEmpty() {
await this.mockRPC("get-project-files?project-id=*", "dashboard/get-project-files-empty.json");
}
async setupSearchEmpty() {
await this.mockRPC("search-files", "dashboard/search-files-empty.json", {
method: "POST",
});
}
async setupLibrariesEmpty() {
await this.mockRPC("get-team-shared-files?team-id=*", "dashboard/get-shared-files-empty.json");
}
async setupDrafts() {
await this.mockRPC("get-project-files?project-id=*", "dashboard/get-project-files.json");
}
@ -74,15 +98,95 @@ export class DashboardPage extends BaseWebSocketPage {
await this.mockRPC("create-project", "dashboard/create-project.json", { method: "POST" });
await this.mockRPC("get-projects?team-id=*", "dashboard/get-projects-new.json");
}
async goToWorkspace() {
async setupDashboardFull() {
await this.mockRPC("get-projects?team-id=*", "dashboard/get-projects-full.json");
await this.mockRPC("get-project-files?project-id=*", "dashboard/get-project-files.json");
await this.mockRPC("get-team-shared-files?team-id=*", "dashboard/get-shared-files.json");
await this.mockRPC("get-team-shared-files?project-id=*", "dashboard/get-shared-files.json");
await this.mockRPC("get-team-recent-files?team-id=*", "dashboard/get-team-recent-files.json");
await this.mockRPC("get-font-variants?team-id=*", "dashboard/get-font-variants.json");
await this.mockRPC("search-files", "dashboard/search-files.json", { method: "POST" });
await this.mockRPC("search-files", "dashboard/search-files.json" );
await this.mockRPC("get-teams", "logged-in-user/get-teams-complete.json");
}
async setupAccessTokensEmpty() {
await this.mockRPC("get-access-tokens", "dashboard/get-access-tokens-empty.json");
}
async createAccessToken() {
await this.mockRPC("create-access-token", "dashboard/create-access-token.json", { method: "POST" });
}
async setupAccessTokens() {
await this.mockRPC("get-access-tokens", "dashboard/get-access-tokens.json");
}
async setupTeamInvitationsEmpty() {
await this.mockRPC("get-team-invitations?team-id=*", "dashboard/get-team-invitations-empty.json");
}
async setupTeamInvitations() {
await this.mockRPC("get-team-invitations?team-id=*", "dashboard/get-team-invitations.json");
}
async setupTeamWebhooksEmpty() {
await this.mockRPC("get-webhooks?team-id=*", "dashboard/get-webhooks-empty.json");
}
async setupTeamWebhooks() {
await this.mockRPC("get-webhooks?team-id=*", "dashboard/get-webhooks.json");
}
async setupTeamSettings() {
await this.mockRPC("get-team-stats?team-id=*", "dashboard/get-team-stats.json");
}
async goToDashboard() {
await this.page.goto(`#/dashboard/team/${DashboardPage.anyTeamId}/projects`);
}
async goToSecondTeamDashboard() {
await this.page.goto(`#/dashboard/team/${DashboardPage.secondTeamId}/projects`);
}
async goToSecondTeamMembersSection() {
await this.page.goto(`#/dashboard/team/${DashboardPage.secondTeamId}/members`);
}
async goToSecondTeamInvitationsSection() {
await this.page.goto(`#/dashboard/team/${DashboardPage.secondTeamId}/invitations`);
}
async goToSecondTeamWebhooksSection() {
await this.page.goto(`#/dashboard/team/${DashboardPage.secondTeamId}/webhooks`);
}
async goToSecondTeamWebhooksSection() {
await this.page.goto(`#/dashboard/team/${DashboardPage.secondTeamId}/webhooks`);
}
async goToSecondTeamSettingsSection() {
await this.page.goto(`#/dashboard/team/${DashboardPage.secondTeamId}/settings`);
}
async goToSearch() {
await this.page.goto(`#/dashboard/team/${DashboardPage.anyTeamId}/search`);
}
async goToDrafts() {
await this.page.goto(
`#/dashboard/team/${DashboardPage.anyTeamId}/projects/${DashboardPage.draftProjectId}`,
);
}
async goToAccount() {
await this.userAccount.click();
await this.userProfileOption.click();
}
}
export default DashboardPage;

View file

@ -13,7 +13,7 @@ test.beforeEach(async ({ page }) => {
test("Dashboad page has title ", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToWorkspace();
await dashboardPage.goToDashboard();
await expect(dashboardPage.page).toHaveURL(/dashboard/);
await expect(dashboardPage.titleLabel).toBeVisible();
@ -23,7 +23,7 @@ test("User can create a new project", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupNewProject();
await dashboardPage.goToWorkspace();
await dashboardPage.goToDashboard();
await dashboardPage.addProjectBtn.click();
await expect(dashboardPage.projectName).toBeVisible();
@ -33,7 +33,7 @@ test("User goes to draft page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDraftsEmpty();
await dashboardPage.goToWorkspace();
await dashboardPage.goToDashboard();
await dashboardPage.draftLink.click();
await expect(dashboardPage.draftTitle).toBeVisible();

View file

@ -12,7 +12,7 @@ test("User can complete the onboarding", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
const onboardingPage = new OnboardingPage(page);
await dashboardPage.goToWorkspace();
await dashboardPage.goToDashboard();
await expect(page.getByRole("heading", { name: "Help us get to know you" })).toBeVisible();
await onboardingPage.fillOnboardingInputsStep1();

View file

@ -0,0 +1,423 @@
import { test, expect } from "@playwright/test";
import DashboardPage from "../pages/DashboardPage";
test.beforeEach(async ({ page }) => {
await DashboardPage.init(page);
await DashboardPage.mockRPC(
page,
"get-profile",
"logged-in-user/get-profile-logged-in-no-onboarding.json",
);
});
test("User goes to an empty dashboard", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await expect(dashboardPage.titleLabel).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
// Empty dashboard pages
test("User goes to an empty draft page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDraftsEmpty();
await dashboardPage.goToDashboard();
await dashboardPage.draftLink.click();
await expect(dashboardPage.draftTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an empty fonts page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.fontsLink.click();
await expect(dashboardPage.fontsTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an empty libraries page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupLibrariesEmpty();
await dashboardPage.goToDashboard();
await dashboardPage.libsLink.click();
await expect(dashboardPage.libsTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an empty search page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupSearchEmpty();
await dashboardPage.goToSearch();
await expect(dashboardPage.searchTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to the dashboard with a new project", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupNewProject();
await dashboardPage.goToDashboard();
await expect(dashboardPage.projectName).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
// Dashboard pages with content
test("User goes to a full dashboard", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToDashboard();
await expect(dashboardPage.draftsFile).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an full draft page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToDashboard();
await dashboardPage.draftLink.click();
await expect(dashboardPage.draftTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an full library page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToDashboard();
await dashboardPage.libsLink.click();
await expect(dashboardPage.libsTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an full fonts page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToDashboard();
await dashboardPage.fontsLink.click();
await expect(dashboardPage.fontsTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an full search page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToSearch();
await expect(dashboardPage.searchInput).toBeVisible();
await dashboardPage.searchInput.fill("New");
await expect(dashboardPage.searchTitle).toBeVisible();
await expect(dashboardPage.newFileName).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
// Account management
test("User opens user account", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await expect(dashboardPage.userAccount).toBeVisible();
await dashboardPage.goToAccount();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to user profile", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.goToAccount();
await expect(dashboardPage.userAccountTitle).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to password management section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.goToAccount();
await page.getByText("Password").click();
await expect(page.getByRole("heading", { name: "Change Password" })).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to settings section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.goToAccount();
await page.getByTestId("settings-profile").click();
await expect(page.getByRole("heading", { name: "Settings" })).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an empty access tokens secction", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.setupAccessTokensEmpty();
await dashboardPage.goToAccount();
await page.getByText("Access tokens").click();
await expect(page.getByRole("heading", { name: "Personal access tokens" })).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User can create an access token", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.setupAccessTokensEmpty();
await dashboardPage.goToAccount();
await page.getByText("Access tokens").click();
await expect(page.getByRole("heading", { name: "Personal access tokens" })).toBeVisible();
await page.getByRole("button", { name: "Generate New Token" }).click();
await dashboardPage.createAccessToken();
await expect(page.getByPlaceholder("The name can help to know")).toBeVisible();
await page.getByPlaceholder("The name can help to know").fill("New token");
await expect(page.getByRole("button", { name: "Create token" })).not.toBeDisabled();
await page.getByRole("button", { name: "Create token" }).click();
await expect(page.getByRole("button", { name: "Create token" })).not.toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to a full access tokens secction", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.setupAccessTokens();
await dashboardPage.goToAccount();
await page.getByText("Access tokens").click();
await expect(page.getByRole("heading", { name: "Personal access tokens" })).toBeVisible();
await expect(page.getByText("new token", { exact: true })).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to the feedback secction", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await dashboardPage.goToAccount();
await page.getByText("Give feedback").click();
await expect(page.getByRole("heading", { name: "Email" })).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
// Teams management
test("User opens teams selector with only one team", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await expect(dashboardPage.titleLabel).toBeVisible();
await dashboardPage.teamDropdown.click();
await expect(page.getByText("Create new team")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User opens teams selector with more than one team", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToDashboard();
await expect(dashboardPage.titleLabel).toBeVisible();
await dashboardPage.teamDropdown.click();
await expect(page.getByText("Second Team")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to second team", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToDashboard();
await dashboardPage.teamDropdown.click();
await expect(page.getByText("Second Team")).toBeVisible();
await page.getByText("Second Team").click();
await expect(page.getByText("Team Up")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User opens team management dropdown", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToSecondTeamDashboard();
await expect(page.getByText("Team Up")).toBeVisible();
await page.getByRole("button", { name: "team-management" }).click();
await expect(page.getByTestId("team-members")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to team management section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.goToSecondTeamMembersSection();
await expect(page.getByText("role")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an empty invitations section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitationsEmpty();
await dashboardPage.goToSecondTeamInvitationsSection();
await expect(page.getByText("No pending invitations")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to a complete invitations section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitations();
await dashboardPage.goToSecondTeamInvitationsSection();
await expect(page.getByText("test1@mail.com")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User invite people to the team", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitationsEmpty();
await dashboardPage.goToSecondTeamInvitationsSection();
await expect(page.getByTestId("invite-member")).toBeVisible();
await page.getByTestId("invite-member").click();
await expect(page.getByText("Invite with the role")).toBeVisible();
await page.getByPlaceholder('Emails, comma separated').fill("test5@mail.com");
await expect(page.getByText("Send invitation")).not.toBeDisabled();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to an empty webhook section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamWebhooksEmpty();
await dashboardPage.goToSecondTeamWebhooksSection();
await expect(page.getByText("No webhooks created so far.")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to a complete webhook section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamWebhooks();
await dashboardPage.goToSecondTeamWebhooksSection();
await expect(page.getByText("https://www.google.com")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});
test("User goes to the team settings section", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamSettings();
await dashboardPage.goToSecondTeamSettingsSection();
await expect(page.getByText("TEAM INFO")).toBeVisible();
await expect(dashboardPage.page).toHaveScreenshot();
});

View file

@ -256,11 +256,13 @@
(if (or @focused? (seq search-term))
[:button {:class (stl/css :search-btn :clear-search-btn)
:tab-index "0"
:aria-label "dashboard-clear-search"
:on-click on-clear-click
:on-key-down handle-clear-search}
clear-search-icon]
[:button {:class (stl/css :search-btn)
:aria-label "dashboard-search"
:on-click on-clear-click}
search-icon])]))
@ -504,11 +506,13 @@
:on-key-down handle-members
:className (stl/css :team-options-item)
:id "teams-options-members"
:data-testid "team-members"
:data-test "team-members"}
(tr "labels.members")]
[:> dropdown-menu-item* {:on-click go-invitations
:on-key-down handle-invitations
:className (stl/css :team-options-item)
:data-testid "team-invitations"
:id "teams-options-invitations"
:data-test "team-invitations"}
(tr "labels.invitations")]
@ -524,6 +528,7 @@
:on-key-down handle-settings
:className (stl/css :team-options-item)
:id "teams-options-settings"
:data-testid "team-settings"
:data-test "team-settings"}
(tr "labels.settings")]
@ -533,6 +538,7 @@
:on-key-down handle-rename
:id "teams-options-rename"
:className (stl/css :team-options-item)
:data-testid "rename-team"
:data-test "rename-team"}
(tr "labels.rename")])
@ -550,6 +556,7 @@
:on-key-down handle-leave-as-owner-clicked
:id "teams-options-leave-team"
:className (stl/css :team-options-item)
:data-testid "leave-team"
:data-test "leave-team"}
(tr "dashboard.leave-team")]
@ -654,6 +661,7 @@
(when-not (:is-default team)
[:button {:class (stl/css :switch-options)
:on-click handle-show-opts-click
:aria-label "team-management"
:tab-index "0"
:on-key-down handle-show-opts-keydown}
menu-icon])]
@ -792,6 +800,7 @@
[:li {:class (stl/css-case :current libs?
:sidebar-nav-item true)}
[:& link {:action go-libs
:data-testid "libs-link-sidebar"
:class (stl/css :sidebar-link)
:keyboard-action go-libs-with-key}
[:span {:class (stl/css :element-title)} (tr "labels.shared-libraries")]]]]]
@ -803,6 +812,7 @@
:current fonts?)}
[:& link {:action go-fonts
:class (stl/css :sidebar-link)
:data-testid "fonts-link-sidebar"
:keyboard-action go-fonts-with-key
:data-test "fonts"}
[:span {:class (stl/css :element-title)} (tr "labels.fonts")]]]]]
@ -946,11 +956,11 @@
:on-hide-comments handle-hide-comments}])
[:div {:class (stl/css :profile-section)}
[:div {:class (stl/css :profile)
:tab-index "0"
:on-click handle-click
:on-key-down handle-key-down
:data-test "profile-btn"}
[:button {:class (stl/css :profile)
:tab-index "0"
:on-click handle-click
:on-key-down handle-key-down
:data-test "profile-btn"}
[:img {:src photo
:class (stl/css :profile-img)
:alt (:fullname profile)}]

View file

@ -331,10 +331,12 @@
}
.profile {
@include buttonStyle;
display: grid;
grid-template-columns: auto 1fr;
gap: $s-8;
cursor: pointer;
text-align: left;
}
.profile-fullname {

View file

@ -105,7 +105,8 @@
[:a
{:class (stl/css :btn-secondary :btn-small)
:on-click on-invite-member
:data-test "invite-member"}
:data-test "invite-member"
:data-testid "invite-member"}
(tr "dashboard.invite-profile")]
[:div {:class (stl/css :blank-space)}])]]))

View file

@ -89,6 +89,7 @@
[:li {:class (stl/css-case :current options?
:settings-item true)
:on-click go-settings-options
:data-testid "settings-profile"
:data-test "settings-profile"}
[:span {:class (stl/css :element-title)} (tr "labels.settings")]]