Skip to content

Commit

Permalink
Add video connect link and Cypress Tests for User Profile (#6924)
Browse files Browse the repository at this point in the history
* Add video connect link to user profile

* Add useAuthUser hook and triggerGoal function

* Refactor DoctorVideoSlideover to filter doctors with alt_phone_number or video_connect_link

* Add user profile tests

* Update input fields with click before clearing and typing
  • Loading branch information
Ashesh3 authored Jan 10, 2024
1 parent f4f9b1e commit 5cf75e8
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 3 deletions.
85 changes: 85 additions & 0 deletions cypress/e2e/users_spec/user_profile.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress";
import LoginPage from "../../pageobject/Login/LoginPage";
import UserProfilePage from "../../pageobject/Users/UserProfilePage";
import ManageUserPage from "../../pageobject/Users/ManageUserPage";

describe("Manage User Profile", () => {
const loginPage = new LoginPage();
const userProfilePage = new UserProfilePage();
const manageUserPage = new ManageUserPage();

const age = "30";
const gender = "Male";
const email = "[email protected]";
const phone = "+918899887788";
const workinghours = "8";
const doctorQualification = "MBBS";
const doctorYoE = "10";
const medicalCouncilRegistration = "1234567890";

const facilitySearch = "Dummy Facility 1";

before(() => {
loginPage.loginAsDevDoctor();
cy.saveLocalStorage();
});

beforeEach(() => {
cy.restoreLocalStorage();
console.log(localStorage);
cy.clearLocalStorage(/filters--.+/);
console.log(localStorage);
cy.awaitUrl("/user/profile");
});

it("Set Age, Gender, Email, Phone and Working Hours for a user and verify its reflection in user profile", () => {
userProfilePage.clickEditProfileButton();

userProfilePage.typeAge(age);
userProfilePage.selectGender(gender);
userProfilePage.typeEmail(email);
userProfilePage.typePhone(phone);
userProfilePage.typeWhatsApp(phone);
userProfilePage.typeWorkingHours(workinghours);
userProfilePage.typeDoctorQualification(doctorQualification);
userProfilePage.typeDoctorYoE(doctorYoE);
userProfilePage.typeMedicalCouncilRegistration(medicalCouncilRegistration);

userProfilePage.clickUpdateButton();

cy.verifyNotification("Details updated successfully");

userProfilePage.assertAge(age);
userProfilePage.assertGender(gender);
userProfilePage.assertEmail(email);
userProfilePage.assertPhone(phone);
userProfilePage.assertWhatsApp(phone);
userProfilePage.assertWorkingHours(workinghours);
});

it("Adding video connect link for a user and verify its reflection in user profile and doctor connect", () => {
// verify the user doesn't have any video connect link
userProfilePage.assertVideoConnectLink("-");
// Link a new video connect link and ensure it is under video connect link
userProfilePage.clickEditProfileButton();
userProfilePage.typeVideoConnectLink("https://www.example.com");
userProfilePage.clickUpdateButton();
userProfilePage.assertVideoConnectLink("https://www.example.com");
// Edit the video connect link and ensure it is updated
userProfilePage.clickEditProfileButton();
userProfilePage.typeVideoConnectLink("https://www.test.com");
userProfilePage.clickUpdateButton();
userProfilePage.assertVideoConnectLink("https://www.test.com");
// Go to particular facility doctor connect and verify the video connect link is present
manageUserPage.navigateToFacility();
manageUserPage.typeFacilitySearch(facilitySearch);
manageUserPage.assertFacilityInCard(facilitySearch);
manageUserPage.clickFacilityPatients();
manageUserPage.clickDoctorConnectButton();
manageUserPage.assertVideoConnectLink("Dev Doctor", "https://www.test.com");
});

afterEach(() => {
cy.saveLocalStorage();
});
});
4 changes: 4 additions & 0 deletions cypress/pageobject/Login/LoginPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ class LoginPage {
cy.loginByApi("devdistrictadmin", "Coronasafe@123");
}

loginAsDevDoctor(): void {
cy.loginByApi("devdoctor", "Coronasafe@123");
}

login(username: string, password: string): void {
cy.loginByApi(username, password);
}
Expand Down
12 changes: 12 additions & 0 deletions cypress/pageobject/Users/ManageUserPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,18 @@ export class ManageUserPage {
cy.get("#doctor-connect-home-doctor").should("contain.text", realName);
cy.get("#doctor-connect-remote-doctor").should("contain.text", realName);
}

assertVideoConnectLink(docName: string, link: string) {
cy.get("ul#options")
.find("li")
.contains(docName)
.within(() => {
cy.get("a").should(($a) => {
const hrefs = $a.map((i, el) => Cypress.$(el).attr("href")).get();
expect(hrefs).to.include(link);
});
});
}
}

export default ManageUserPage;
84 changes: 84 additions & 0 deletions cypress/pageobject/Users/UserProfilePage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
export default class UserProfilePage {
assertVideoConnectLink(link: string) {
cy.get("#videoconnectlink-profile-details").should("contain.text", link);
}

clickEditProfileButton() {
cy.get("#edit-cancel-profile-button").click();
}

typeVideoConnectLink(link: string) {
cy.get("#video_connect_link").click().clear().type(link);
}

clickUpdateButton() {
cy.get("#submit").click();
}

typeAge(age: string) {
cy.get("#age").click().clear().type(age);
}

selectGender(gender: string) {
cy.get("#gender").click();
cy.get("#gender-option-" + gender).click();
}

typeEmail(email: string) {
cy.get("#email").click().clear().type(email);
}

typePhone(phone: string) {
cy.get("#phoneNumber").click().clear().type(phone);
}

typeWhatsApp(phone: string) {
cy.get("#altPhoneNumber").click().clear().type(phone);
}

typeWorkingHours(workinghours: string) {
cy.get("#weekly_working_hours").click().clear().type(workinghours);
}

typeDoctorQualification = (doctorQualification: string) => {
cy.get("#doctor_qualification").click().clear().type(doctorQualification);
};

typeDoctorYoE = (doctorYoE: string) => {
cy.get("#doctor_experience_commenced_on").click().clear().type(doctorYoE);
};

typeMedicalCouncilRegistration = (medicalCouncilRegistration: string) => {
cy.get("#doctor_medical_council_registration")
.click()
.clear()
.type(medicalCouncilRegistration);
};

assertAge(age: string) {
cy.get("#age-profile-details").should("contain.text", age);
}

assertGender(gender: string) {
cy.get("#gender-profile-details").should("contain.text", gender);
}

assertEmail(email: string) {
cy.get("#emailid-profile-details").should("contain.text", email);
}

assertPhone(phone: string) {
cy.get("#contactno-profile-details").should("contain.text", phone);
}

assertWhatsApp(phone: string) {
cy.get("#whatsapp-profile-details").should("contain.text", phone);
}

assertWorkingHours(workinghours: string) {
cy.get("#averageworkinghour-profile-details").should(
"contain.text",
workinghours
);
}
}
44 changes: 42 additions & 2 deletions src/Components/Facility/DoctorVideoSlideover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { UserAssignedModel } from "../Users/models";
import { SkillObjectModel } from "../Users/models";
import CareIcon from "../../CAREUI/icons/CareIcon";
import { relativeTime } from "../../Utils/utils";
import useAuthUser from "../../Common/hooks/useAuthUser";
import { triggerGoal } from "../../Integrations/Plausible";

export default function DoctorVideoSlideover(props: {
show: boolean;
Expand All @@ -22,10 +24,12 @@ export default function DoctorVideoSlideover(props: {
const res = await dispatchAction(
getFacilityUsers(facilityId, { limit: 50 })
);
if (res && res.data) {
if (res?.data) {
setDoctors(
res.data.results
.filter((user: any) => user.alt_phone_number)
.filter(
(user: any) => user.alt_phone_number || user.video_connect_link
)
.sort((a: any, b: any) => {
return Number(a.last_login) - Number(b.last_login);
})
Expand Down Expand Up @@ -106,6 +110,7 @@ function UserListItem(props: { user: UserAssignedModel }) {
const user = props.user;
const icon =
user.user_type === "Doctor" ? "fa-user-doctor " : " fa-user-nurse";
const authUser = useAuthUser();

return (
<li>
Expand Down Expand Up @@ -152,6 +157,27 @@ function UserListItem(props: { user: UserAssignedModel }) {
{user.first_name} {user.last_name}
</span>
<div className="flex gap-2">
{user.video_connect_link && (
<a
href={user.video_connect_link}
onClick={() => {
triggerGoal("Doctor Connect Click", {
medium: "Video Call",
userId: authUser?.id,
targetUserType: user.user_type,
});
}}
target="_blank"
rel="noopener noreferrer"
>
<div className="tooltip">
<span className="tooltip-text tooltip-left">
Connect on a Video Call
</span>
<CareIcon icon="l-video" className="h-5 w-5" />
</div>
</a>
)}
<a
href={
user.alt_phone_number
Expand All @@ -162,6 +188,13 @@ function UserListItem(props: { user: UserAssignedModel }) {
)}`
: "#"
}
onClick={() => {
triggerGoal("Doctor Connect Click", {
medium: "WhatsApp",
userId: authUser?.id,
targetUserType: user.user_type,
});
}}
target="_blank"
rel="noopener noreferrer"
>
Expand All @@ -176,6 +209,13 @@ function UserListItem(props: { user: UserAssignedModel }) {
href={
user.alt_phone_number ? `tel:${user.alt_phone_number}` : "#"
}
onClick={() => {
triggerGoal("Doctor Connect Click", {
medium: "Phone Call",
userId: authUser?.id,
targetUserType: user.user_type,
});
}}
>
<div className="tooltip">
<span className="tooltip-text tooltip-left">
Expand Down
43 changes: 42 additions & 1 deletion src/Components/Users/UserProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as Notification from "../../Utils/Notifications.js";
import LanguageSelector from "../../Components/Common/LanguageSelector";
import TextFormField from "../Form/FormFields/TextFormField";
import ButtonV2, { Submit } from "../Common/components/ButtonV2";
import { classNames, parsePhoneNumber } from "../../Utils/utils";
import { classNames, isValidUrl, parsePhoneNumber } from "../../Utils/utils";
import CareIcon from "../../CAREUI/icons/CareIcon";
import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField";
import { FieldChangeEvent } from "../Form/FormFields/Utils";
Expand All @@ -27,6 +27,7 @@ type EditForm = {
age: string;
gender: GenderType;
email: string;
video_connect_link: string | undefined;
phoneNumber: string;
altPhoneNumber: string;
user_type: string | undefined;
Expand All @@ -41,6 +42,7 @@ type ErrorForm = {
age: string;
gender: string;
email: string;
video_connect_link: string | undefined;
phoneNumber: string;
altPhoneNumber: string;
user_type: string | undefined;
Expand All @@ -62,6 +64,7 @@ const initForm: EditForm = {
lastName: "",
age: "",
gender: "Male",
video_connect_link: "",
email: "",
phoneNumber: "",
altPhoneNumber: "",
Expand Down Expand Up @@ -145,6 +148,7 @@ export default function UserProfile() {
age: result.data.age?.toString() || "",
gender: result.data.gender || "Male",
email: result.data.email,
video_connect_link: result.data.video_connect_link,
phoneNumber: result.data.phone_number?.toString() || "",
altPhoneNumber: result.data.alt_phone_number?.toString() || "",
user_type: result.data.user_type,
Expand Down Expand Up @@ -262,6 +266,14 @@ export default function UserProfile() {
invalidForm = true;
}
return;
case "video_connect_link":
if (states.form[field]) {
if (isValidUrl(states.form[field]) === false) {
errors[field] = "Please enter a valid url";
invalidForm = true;
}
}
return;
}
});
dispatch({ type: "set_error", errors });
Expand Down Expand Up @@ -294,6 +306,7 @@ export default function UserProfile() {
first_name: states.form.firstName,
last_name: states.form.lastName,
email: states.form.email,
video_connect_link: states.form.video_connect_link,
phone_number: parsePhoneNumber(states.form.phoneNumber) ?? "",
alt_phone_number: parsePhoneNumber(states.form.altPhoneNumber) ?? "",
gender: states.form.gender,
Expand Down Expand Up @@ -578,6 +591,28 @@ export default function UserProfile() {
{userData?.weekly_working_hours || "-"}
</dd>
</div>
<div
className="my-2 sm:col-span-2"
id="videoconnectlink-profile-details"
>
<dt className="text-sm font-medium leading-5 text-black">
Video Connect Link
</dt>
<dd className="mt-1 break-words text-sm leading-5 text-gray-900">
{userData?.video_connect_link ? (
<a
className="text-blue-500"
href={userData?.video_connect_link}
target="_blank"
rel="noreferrer"
>
{userData?.video_connect_link}
</a>
) : (
"-"
)}
</dd>
</div>
</dl>
</div>
)}
Expand Down Expand Up @@ -679,6 +714,12 @@ export default function UserProfile() {
min={0}
max={168}
/>
<TextFormField
{...fieldProps("video_connect_link")}
label="Video Conference Link"
className="col-span-6 sm:col-span-6"
type="url"
/>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 text-right sm:px-6">
Expand Down
Loading

0 comments on commit 5cf75e8

Please sign in to comment.