diff --git a/app/client/cypress/fixtures/Files/invalid-image.png b/app/client/cypress/fixtures/Files/invalid-image.png new file mode 100644 index 0000000000..dbf091df9a --- /dev/null +++ b/app/client/cypress/fixtures/Files/invalid-image.png @@ -0,0 +1,198 @@ +%PDF-1.3 +%âãÏÓ + +1 0 obj +<< +/Type /Catalog +/Outlines 2 0 R +/Pages 3 0 R +>> +endobj + +2 0 obj +<< +/Type /Outlines +/Count 0 +>> +endobj + +3 0 obj +<< +/Type /Pages +/Count 2 +/Kids [ 4 0 R 6 0 R ] +>> +endobj + +4 0 obj +<< +/Type /Page +/Parent 3 0 R +/Resources << +/Font << +/F1 9 0 R +>> +/ProcSet 8 0 R +>> +/MediaBox [0 0 612.0000 792.0000] +/Contents 5 0 R +>> +endobj + +5 0 obj +<< /Length 1074 >> +stream +2 J +BT +0 0 0 rg +/F1 0027 Tf +57.3750 722.2800 Td +( A Simple PDF File ) Tj +ET +BT +/F1 0010 Tf +69.2500 688.6080 Td +( This is a small demonstration .pdf file - ) Tj +ET +BT +/F1 0010 Tf +69.2500 664.7040 Td +( just for use in the Virtual Mechanics tutorials. More text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 652.7520 Td +( text. And more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 628.8480 Td +( And more text. And more text. And more text. And more text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 616.8960 Td +( text. And more text. Boring, zzzzz. And more text. And more text. And ) Tj +ET +BT +/F1 0010 Tf +69.2500 604.9440 Td +( more text. And more text. And more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 592.9920 Td +( And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 569.0880 Td +( And more text. And more text. And more text. And more text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 557.1360 Td +( text. And more text. And more text. Even more. Continued on page 2 ...) Tj +ET +endstream +endobj + +6 0 obj +<< +/Type /Page +/Parent 3 0 R +/Resources << +/Font << +/F1 9 0 R +>> +/ProcSet 8 0 R +>> +/MediaBox [0 0 612.0000 792.0000] +/Contents 7 0 R +>> +endobj + +7 0 obj +<< /Length 676 >> +stream +2 J +BT +0 0 0 rg +/F1 0027 Tf +57.3750 722.2800 Td +( Simple PDF File 2 ) Tj +ET +BT +/F1 0010 Tf +69.2500 688.6080 Td +( ...continued from page 1. Yet more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 676.6560 Td +( And more text. And more text. And more text. And more text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 664.7040 Td +( text. Oh, how boring typing this stuff. But not as boring as watching ) Tj +ET +BT +/F1 0010 Tf +69.2500 652.7520 Td +( paint dry. And more text. And more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 640.8000 Td +( Boring. More, a little more text. The end, and just as well. ) Tj +ET +endstream +endobj + +8 0 obj +[/PDF /Text] +endobj + +9 0 obj +<< +/Type /Font +/Subtype /Type1 +/Name /F1 +/BaseFont /Helvetica +/Encoding /WinAnsiEncoding +>> +endobj + +10 0 obj +<< +/Creator (Rave \(http://www.nevrona.com/rave\)) +/Producer (Nevrona Designs) +/CreationDate (D:20060301072826) +>> +endobj + +xref +0 11 +0000000000 65535 f +0000000019 00000 n +0000000093 00000 n +0000000147 00000 n +0000000222 00000 n +0000000390 00000 n +0000001522 00000 n +0000001690 00000 n +0000002423 00000 n +0000002456 00000 n +0000002574 00000 n + +trailer +<< +/Size 11 +/Root 1 0 R +/Info 10 0 R +>> + +startxref +2714 +%%EOF diff --git a/app/client/cypress/fixtures/Files/valid-image.jpeg b/app/client/cypress/fixtures/Files/valid-image.jpeg new file mode 100644 index 0000000000..54665a85ea Binary files /dev/null and b/app/client/cypress/fixtures/Files/valid-image.jpeg differ diff --git a/app/client/cypress/integration/Regression_TestSuite/ClientSideTests/UserProfile/UpdateUserPicture_spec.js b/app/client/cypress/integration/Regression_TestSuite/ClientSideTests/UserProfile/UpdateUserPicture_spec.js new file mode 100644 index 0000000000..ca1524ce6d --- /dev/null +++ b/app/client/cypress/integration/Regression_TestSuite/ClientSideTests/UserProfile/UpdateUserPicture_spec.js @@ -0,0 +1,56 @@ +import homePage from "../../../../locators/HomePage"; +import * as _ from "../../../../support/Objects/ObjectsCore"; + +describe("Update a user's display picture", function () { + beforeEach(() => { + _.homePage.GotoEditProfile(); + + _.agHelper.GetText(_.locators._ds_imageSelector_label).then((text) => { + text === "Remove" && + _.agHelper.GetNClick(_.locators._ds_imageSelector_label); + }); + + // API is finished even before wait begins + // cy.intercept("GET", "/api/v1/users/photo", { + // body: { responseMeta: { status: 200, success: true }, data: {} }, + // }).as("savePhoto"); + }); + + it("1. Update a user's picture with valid file", function () { + _.agHelper.GetNClick(_.locators._ds_imageSelector); + _.agHelper.GetElement(_.locators._ds_uppy_fileInput).as("fileInput"); + + cy.fixture("Files/valid-image.jpeg").then((fileContent) => { + _.agHelper.GetElement("@fileInput").attachFile({ + fileContent: fileContent.toString(), + fileName: "valid-image.jpeg", + mimeType: "image/jpeg", + encoding: "base64", + }); + + _.agHelper.GetNClick(_.locators._ds_uppy_crop_confirm); + _.agHelper.GetNClick(_.locators._ds_uppy_upload_btn); + // API is finished even before wait begins + // cy.wait("@savePhoto"); + _.agHelper.AssertElementExist(".image-view img"); + }); + }); + + it("2. Invalid file throws error", function () { + _.agHelper.GetNClick(_.locators._ds_imageSelector); + _.agHelper.GetElement(_.locators._ds_uppy_fileInput).as("fileInput"); + + cy.fixture("Files/invalid-image.png").then((fileContent) => { + _.agHelper.GetElement("@fileInput").attachFile({ + fileContent: fileContent.toString(), + fileName: "invalid-image.png", + mimeType: "image/png", + encoding: "base64", + }); + + _.agHelper.ValidateToastMessage( + "File content doesn't seem to be an image. Please verify.", + ); + }); + }); +}); diff --git a/app/client/cypress/integration/Regression_TestSuite/ClientSideTests/ExplorerTests/UpdateUsersName_spec.js b/app/client/cypress/integration/Regression_TestSuite/ClientSideTests/UserProfile/UpdateUsersName_spec.js similarity index 100% rename from app/client/cypress/integration/Regression_TestSuite/ClientSideTests/ExplorerTests/UpdateUsersName_spec.js rename to app/client/cypress/integration/Regression_TestSuite/ClientSideTests/UserProfile/UpdateUsersName_spec.js diff --git a/app/client/cypress/support/Objects/CommonLocators.ts b/app/client/cypress/support/Objects/CommonLocators.ts index 0d8ff0db99..95fc95ffad 100644 --- a/app/client/cypress/support/Objects/CommonLocators.ts +++ b/app/client/cypress/support/Objects/CommonLocators.ts @@ -180,4 +180,10 @@ export class CommonLocators { _canvas = "[data-testid=widgets-editor]"; _enterPreviewMode = "[data-cy='edit-mode']"; _exitPreviewMode = "[data-cy='preview-mode']"; + + _ds_imageSelector = ".ads-dialog-trigger"; + _ds_imageSelector_label = ".ads-dialog-trigger .label"; + _ds_uppy_fileInput = ".uppy-Dashboard-input"; + _ds_uppy_crop_confirm = ".uppy-ImageCropper-controls .uppy-c-btn"; + _ds_uppy_upload_btn = ".uppy-StatusBar-actionBtn--upload"; } diff --git a/app/client/cypress/support/Pages/HomePage.ts b/app/client/cypress/support/Pages/HomePage.ts index c61cf31b4d..718531d600 100644 --- a/app/client/cypress/support/Pages/HomePage.ts +++ b/app/client/cypress/support/Pages/HomePage.ts @@ -38,6 +38,7 @@ export class HomePage { role + "']"; private _profileMenu = ".t--profile-menu"; + private _editProfileMenu = ".t--edit-profile"; private _signout = ".t--logout-icon"; _searchUsersInput = ".search-input"; @@ -272,6 +273,20 @@ export class HomePage { this.agHelper.Sleep(); //for logout to complete! } + public GotoProfileMenu() { + this.agHelper.GetNClick(this._profileMenu); + } + + public GotoEditProfile() { + cy.location().then((loc) => { + if (loc.pathname !== "/profile") { + this.NavigateToHome(); + this.GotoProfileMenu(); + this.agHelper.GetNClick(this._editProfileMenu); + } + }); + } + public LogintoApp( uname: string, pswd: string, diff --git a/app/client/package.json b/app/client/package.json index 4c77efd8eb..77882e85bb 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -80,7 +80,7 @@ "cypress-log-to-output": "^1.1.2", "dayjs": "^1.10.6", "deep-diff": "^1.0.2", - "design-system-old": "npm:@appsmithorg/design-system-old@1.1.5", + "design-system-old": "npm:@appsmithorg/design-system-old@1.1.6", "downloadjs": "^1.4.7", "exceljs": "^4.3.0", "fast-deep-equal": "^3.1.3", diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index c0ffff9aa0..fa8b6c26c9 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -984,6 +984,7 @@ export const ReduxActionErrorTypes = { INSTALL_LIBRARY_FAILED: "INSTALL_LIBRARY_FAILED", UNINSTALL_LIBRARY_FAILED: "UNINSTALL_LIBRARY_FAILED", FETCH_JS_LIBRARIES_FAILED: "FETCH_JS_LIBRARIES_FAILED", + USER_IMAGE_INVALID_FILE_CONTENT: "USER_IMAGE_INVALID_FILE_CONTENT", }; export const ReduxFormActionTypes = { diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index fdbabc79fa..96a3a0da97 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -173,6 +173,8 @@ export const NO_USERS_INVITED = () => "You haven't invited any users yet"; export const UPDATE_USER_DETAILS_FAILED = () => "Unable to update user details."; +export const USER_DISPLAY_PICTURE_FILE_INVALID = () => + "File content doesn't seem to be an image. Please verify."; export const CREATE_PASSWORD_RESET_SUCCESS = () => `Your password has been set`; export const CREATE_PASSWORD_RESET_SUCCESS_LOGIN_LINK = () => `Login`; diff --git a/app/client/src/pages/UserProfile/UserProfileImagePicker.tsx b/app/client/src/pages/UserProfile/UserProfileImagePicker.tsx index 499e5a20c2..e14e9f6770 100644 --- a/app/client/src/pages/UserProfile/UserProfileImagePicker.tsx +++ b/app/client/src/pages/UserProfile/UserProfileImagePicker.tsx @@ -8,6 +8,9 @@ import { DisplayImageUpload } from "design-system-old"; import type Uppy from "@uppy/core"; import { isAirgapped } from "@appsmith/utils/airgapHelpers"; +import { ReduxActionErrorTypes } from "ce/constants/ReduxActionConstants"; +import type { ErrorActionPayload } from "sagas/ErrorSagas"; +import { USER_DISPLAY_PICTURE_FILE_INVALID } from "ce/constants/messages"; function FormDisplayImage() { const isAirgappedInstance = isAirgapped(); @@ -53,10 +56,24 @@ function FormDisplayImage() { ); }; + const onFileTypeInvalid = () => { + const payload: ErrorActionPayload = { + show: true, + error: { + message: USER_DISPLAY_PICTURE_FILE_INVALID(), + }, + }; + dispatch({ + type: ReduxActionErrorTypes.USER_IMAGE_INVALID_FILE_CONTENT, + payload, + }); + }; + return (