From 7ed62cfc0e0fb6e96712bac56cdec049dfb1fcf4 Mon Sep 17 00:00:00 2001 From: Simran Kaur Date: Mon, 30 Sep 2024 12:08:49 -0400 Subject: [PATCH 1/6] testing environment seems to be working for basic tests. currently facing issues mocking a login before tests --- tests/e2e/submit-testimony.spec.ts | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/e2e/submit-testimony.spec.ts diff --git a/tests/e2e/submit-testimony.spec.ts b/tests/e2e/submit-testimony.spec.ts new file mode 100644 index 000000000..1c8e2f5ab --- /dev/null +++ b/tests/e2e/submit-testimony.spec.ts @@ -0,0 +1,52 @@ +import { test, expect } from "@playwright/test" +const testBillPage = "http://localhost:3000/bills/193/S2097" + +test("is my stuff running", async ({ page }) => { + await page.goto("http://localhost:3000") + await page.getByRole("button", { name: "Browse All Testimony" }).click() + await page.waitForURL(/\/testimony/) + await expect(page).toHaveURL(/\/testimony/) +}) + +// test.describe("When user is not signed in", ()=>{ +// test("should display login/signup button on a bill page", async({page})=>{ + +// }) +// test("should redirect to login/signup when button is clicked", async({page})=>{ + +// }) +// }) + +test.describe("Submit Testimony Flow for logged in User", () => { + test.beforeEach(async ({ page }) => { + // Log in the user + await page.goto("http://localhost:3000") + await page.getByRole("button", { name: "Log in / Sign up" }).click() + await page.getByRole("button", { name: "Sign In", exact: true }).click() + await page.fill('input[name="email"]', "testimonysubmit@gmail.com") // Use test user credentials + await page.fill('input[name="password"]', "maple123@") + await page + .getByLabel("Sign In", { exact: true }) + .getByRole("button", { name: "Sign In" }) + .click() + }) + + test("should display Create Testimony Button", async ({ page }) => { + await page.goto(testBillPage) + // await page.getByRole('button',{name:'Create Testimony'}).click() + // await expect(page).toHaveURL(/.*submit-testimony/) + const buttons = await page.$$("button") + + // Extract text content from each button + const buttonTexts = [] + for (const button of buttons) { + const text = await button.innerText() // Get the button's text + buttonTexts.push(text) // Add the text to the array + } + + // Log the button texts to the console + console.log("Buttons on the page:", buttonTexts) + }) + + // test("should redirect to submit testimonu rl when button is selected") +}) From eb5dc19ad9c394fa16591b30db322ef42d6d4869 Mon Sep 17 00:00:00 2001 From: Simran Kaur Date: Mon, 30 Sep 2024 15:57:48 -0400 Subject: [PATCH 2/6] tests are running with before-each setting the login information. still getting occadional timeout errors from firefox --- tests/e2e/submit-testimony.spec.ts | 57 ++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/tests/e2e/submit-testimony.spec.ts b/tests/e2e/submit-testimony.spec.ts index 1c8e2f5ab..305758c45 100644 --- a/tests/e2e/submit-testimony.spec.ts +++ b/tests/e2e/submit-testimony.spec.ts @@ -1,5 +1,8 @@ import { test, expect } from "@playwright/test" -const testBillPage = "http://localhost:3000/bills/193/S2097" +import { BillPage } from "./page_objects/billPage" +const testUserEmail = "testimonysubmit@gmail.com" +const testUserPassword = "maple123@" + test("is my stuff running", async ({ page }) => { await page.goto("http://localhost:3000") @@ -23,30 +26,46 @@ test.describe("Submit Testimony Flow for logged in User", () => { await page.goto("http://localhost:3000") await page.getByRole("button", { name: "Log in / Sign up" }).click() await page.getByRole("button", { name: "Sign In", exact: true }).click() - await page.fill('input[name="email"]', "testimonysubmit@gmail.com") // Use test user credentials - await page.fill('input[name="password"]', "maple123@") + await page.fill('input[name="email"]', testUserEmail) // Use test user credentials + await page.fill('input[name="password"]', testUserPassword) await page .getByLabel("Sign In", { exact: true }) .getByRole("button", { name: "Sign In" }) .click() + const profileIcon = page.getByAltText("profile icon") + await expect(profileIcon).toBeVisible() + }) - test("should display Create Testimony Button", async ({ page }) => { - await page.goto(testBillPage) - // await page.getByRole('button',{name:'Create Testimony'}).click() - // await expect(page).toHaveURL(/.*submit-testimony/) - const buttons = await page.$$("button") - - // Extract text content from each button - const buttonTexts = [] - for (const button of buttons) { - const text = await button.innerText() // Get the button's text - buttonTexts.push(text) // Add the text to the array - } - - // Log the button texts to the console - console.log("Buttons on the page:", buttonTexts) + test("should navigate to a bill", async ({ page }) => { + // click browse bills + await page.getByRole("link",{name:"Browse Bills"}).first().click() + + // select the first bill in the list + const firstBillLink = page.locator('a[href*="/bills"]').first(); + await firstBillLink.click() + }) - // test("should redirect to submit testimonu rl when button is selected") + test("should successfully submit testimony when starting from the bills page",async({page})=>{ + + // go to browse bills page + await page.goto("http://localhost:3000/bills") + await page.waitForSelector("li.ais-Hits-item a") + + // click the first bill + const billpage = new BillPage(page) + await billpage.clickFirstBill() + await page.screenshot({ path: 'screenshot.png' }); + + // click the create testimony button + const createTestimonyButton = page.getByRole("button",{name: "Create Testimony"}) + await expect(createTestimonyButton).toBeVisible() + await page.screenshot({ path: 'screenshot.png' }); + await createTestimonyButton.click() + + + + + }) }) From 3edd4df410185cfe637296756270059d47f2b32f Mon Sep 17 00:00:00 2001 From: Simran Kaur Date: Tue, 1 Oct 2024 11:17:31 -0400 Subject: [PATCH 3/6] debugging timeout errors related to create testimony button --- tests/e2e/submit-testimony.spec.ts | 64 ++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/tests/e2e/submit-testimony.spec.ts b/tests/e2e/submit-testimony.spec.ts index 305758c45..e04080332 100644 --- a/tests/e2e/submit-testimony.spec.ts +++ b/tests/e2e/submit-testimony.spec.ts @@ -3,14 +3,6 @@ import { BillPage } from "./page_objects/billPage" const testUserEmail = "testimonysubmit@gmail.com" const testUserPassword = "maple123@" - -test("is my stuff running", async ({ page }) => { - await page.goto("http://localhost:3000") - await page.getByRole("button", { name: "Browse All Testimony" }).click() - await page.waitForURL(/\/testimony/) - await expect(page).toHaveURL(/\/testimony/) -}) - // test.describe("When user is not signed in", ()=>{ // test("should display login/signup button on a bill page", async({page})=>{ @@ -34,21 +26,20 @@ test.describe("Submit Testimony Flow for logged in User", () => { .click() const profileIcon = page.getByAltText("profile icon") await expect(profileIcon).toBeVisible() - }) test("should navigate to a bill", async ({ page }) => { // click browse bills - await page.getByRole("link",{name:"Browse Bills"}).first().click() + await page.getByRole("link", { name: "Browse Bills" }).first().click() // select the first bill in the list - const firstBillLink = page.locator('a[href*="/bills"]').first(); + const firstBillLink = page.locator('a[href*="/bills"]').first() await firstBillLink.click() - }) - test("should successfully submit testimony when starting from the bills page",async({page})=>{ - + test("should successfully submit testimony when starting from the bills page", async ({ + page + }) => { // go to browse bills page await page.goto("http://localhost:3000/bills") await page.waitForSelector("li.ais-Hits-item a") @@ -56,16 +47,49 @@ test.describe("Submit Testimony Flow for logged in User", () => { // click the first bill const billpage = new BillPage(page) await billpage.clickFirstBill() - await page.screenshot({ path: 'screenshot.png' }); - + console.log("Clicked first bill") + + // wait for URL change + await page.waitForURL(/\/bills\/\d+/, { timeout: 10000 }) + console.log("URL changed to bill detail") + const currentUrl = page.url() + console.log("Current URL:", currentUrl) + + // Listen for failed requests + page.on("requestfailed", request => { + console.log(`Failed request: ${request.url()}`) + }) + + // take screenshot + await page.screenshot({ path: "screenshot.png" }) + console.log("Screenshot taken") + + // Wait for create testimony bnutton to become visible + const createTestimonyButton = page.getByRole("button", { + name: "Create Testimony" + }) + console.log("Waiting for Create Testimony button...") + await page.waitForSelector( + 'button:has-text("Create") , button:has-text("Testimony")', + { state: "visible", timeout: 30000 } + ) + console.log("Create Testimony button is visible") + await expect(createTestimonyButton).toBeVisible({ timeout: 30000 }) // click the create testimony button - const createTestimonyButton = page.getByRole("button",{name: "Create Testimony"}) - await expect(createTestimonyButton).toBeVisible() - await page.screenshot({ path: 'screenshot.png' }); await createTestimonyButton.click() + // expect to see all stance options + const endorseRadioButton = page.getByLabel("Endorse") + const neutralRadioButton = page.getByLabel("Neutral") + const opposeRadioButton = page.getByLabel("Oppose") + // can click any stance option + await endorseRadioButton.click({ force: true }) + await neutralRadioButton.click() + await opposeRadioButton.click() - + // clicking next with oppose selected + const nextButton = page.getByRole("button", { name: "Next >>" }) + await nextButton.click() }) }) From 05c73721cfc5c87c25e3cba5500a566de6acb5b0 Mon Sep 17 00:00:00 2001 From: Simran Kaur Date: Tue, 1 Oct 2024 21:14:13 -0400 Subject: [PATCH 4/6] still troubleshooting. added a networkidle log --- tests/e2e/submit-testimony.spec.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/e2e/submit-testimony.spec.ts b/tests/e2e/submit-testimony.spec.ts index e04080332..e87d22213 100644 --- a/tests/e2e/submit-testimony.spec.ts +++ b/tests/e2e/submit-testimony.spec.ts @@ -26,6 +26,7 @@ test.describe("Submit Testimony Flow for logged in User", () => { .click() const profileIcon = page.getByAltText("profile icon") await expect(profileIcon).toBeVisible() + }) test("should navigate to a bill", async ({ page }) => { @@ -50,7 +51,7 @@ test.describe("Submit Testimony Flow for logged in User", () => { console.log("Clicked first bill") // wait for URL change - await page.waitForURL(/\/bills\/\d+/, { timeout: 10000 }) + await page.waitForURL(/\/bills\/\d+/) console.log("URL changed to bill detail") const currentUrl = page.url() console.log("Current URL:", currentUrl) @@ -59,11 +60,15 @@ test.describe("Submit Testimony Flow for logged in User", () => { page.on("requestfailed", request => { console.log(`Failed request: ${request.url()}`) }) - + + // wait for network idle + await page.waitForLoadState('networkidle'); + console.log("network idle") + // take screenshot await page.screenshot({ path: "screenshot.png" }) console.log("Screenshot taken") - + // Wait for create testimony bnutton to become visible const createTestimonyButton = page.getByRole("button", { name: "Create Testimony" @@ -71,10 +76,10 @@ test.describe("Submit Testimony Flow for logged in User", () => { console.log("Waiting for Create Testimony button...") await page.waitForSelector( 'button:has-text("Create") , button:has-text("Testimony")', - { state: "visible", timeout: 30000 } + { state: "visible" } ) console.log("Create Testimony button is visible") - await expect(createTestimonyButton).toBeVisible({ timeout: 30000 }) + await expect(createTestimonyButton).toBeVisible() // click the create testimony button await createTestimonyButton.click() From 4b203483882a2cc7c3b7def1b3992e608f57e14d Mon Sep 17 00:00:00 2001 From: Simran Kaur Date: Fri, 18 Oct 2024 11:54:11 -0400 Subject: [PATCH 5/6] test(e2e): fix timeout error when clicking create testimony Fixed an issue where the tests would time out when clicking the 'Create Testimony' button in the submit testimony test. Now that I am using getByRole to find the button instead of waitForSelector, all browsers except firefox pass this part of the test. Firefox fails waiting for profile icon in the beforeEach block. --- .gitignore | 1 + tests/e2e/submit-testimony.spec.ts | 61 ++++++++++++------------------ 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index b1816690d..4360c9a37 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ _static .env.development.local .env.test.local .env.production.local +.env npm-debug.log* yarn-debug.log* diff --git a/tests/e2e/submit-testimony.spec.ts b/tests/e2e/submit-testimony.spec.ts index e87d22213..0b7f21e20 100644 --- a/tests/e2e/submit-testimony.spec.ts +++ b/tests/e2e/submit-testimony.spec.ts @@ -1,7 +1,16 @@ import { test, expect } from "@playwright/test" import { BillPage } from "./page_objects/billPage" -const testUserEmail = "testimonysubmit@gmail.com" -const testUserPassword = "maple123@" +require("dotenv").config() + +const testUserEmail = process.env.TEST_USERNAME +const testUserPassword = process.env.TEST_PASSWORD + +// Ensure user credentials are set, otherwise throw an error +if (!testUserEmail || !testUserPassword) { + throw new Error( + "Admin credentials are not defined in the environment variables." + ) +} // test.describe("When user is not signed in", ()=>{ // test("should display login/signup button on a bill page", async({page})=>{ @@ -26,7 +35,6 @@ test.describe("Submit Testimony Flow for logged in User", () => { .click() const profileIcon = page.getByAltText("profile icon") await expect(profileIcon).toBeVisible() - }) test("should navigate to a bill", async ({ page }) => { @@ -38,7 +46,7 @@ test.describe("Submit Testimony Flow for logged in User", () => { await firstBillLink.click() }) - test("should successfully submit testimony when starting from the bills page", async ({ + test("should successfully submit testimony", async ({ page }) => { // go to browse bills page @@ -48,7 +56,6 @@ test.describe("Submit Testimony Flow for logged in User", () => { // click the first bill const billpage = new BillPage(page) await billpage.clickFirstBill() - console.log("Clicked first bill") // wait for URL change await page.waitForURL(/\/bills\/\d+/) @@ -56,45 +63,27 @@ test.describe("Submit Testimony Flow for logged in User", () => { const currentUrl = page.url() console.log("Current URL:", currentUrl) - // Listen for failed requests - page.on("requestfailed", request => { - console.log(`Failed request: ${request.url()}`) - }) - - // wait for network idle - await page.waitForLoadState('networkidle'); - console.log("network idle") - // take screenshot await page.screenshot({ path: "screenshot.png" }) console.log("Screenshot taken") - - // Wait for create testimony bnutton to become visible - const createTestimonyButton = page.getByRole("button", { - name: "Create Testimony" - }) - console.log("Waiting for Create Testimony button...") - await page.waitForSelector( - 'button:has-text("Create") , button:has-text("Testimony")', - { state: "visible" } - ) - console.log("Create Testimony button is visible") - await expect(createTestimonyButton).toBeVisible() - // click the create testimony button - await createTestimonyButton.click() + + + // click create testimony + await page.getByRole("button", { name: "Create Testimony"}).click() + await page.screenshot({ path: "screenshot.png" }) // expect to see all stance options - const endorseRadioButton = page.getByLabel("Endorse") - const neutralRadioButton = page.getByLabel("Neutral") - const opposeRadioButton = page.getByLabel("Oppose") + // const endorseRadioButton = page.getByLabel("Endorse") + // const neutralRadioButton = page.getByLabel("Neutral") + // const opposeRadioButton = page.getByLabel("Oppose") // can click any stance option - await endorseRadioButton.click({ force: true }) - await neutralRadioButton.click() - await opposeRadioButton.click() + // await endorseRadioButton.click({ force: true }) + // await neutralRadioButton.click() + // await opposeRadioButton.click() // clicking next with oppose selected - const nextButton = page.getByRole("button", { name: "Next >>" }) - await nextButton.click() + // const nextButton = page.getByRole("button", { name: "Next >>" }) + // await nextButton.click() }) }) From 23274201e2fd0be8dd125989dd30782b1bad1a6f Mon Sep 17 00:00:00 2001 From: Simran Kaur Date: Wed, 23 Oct 2024 16:41:54 -0400 Subject: [PATCH 6/6] add fake user object in export data json file --- tests/integration/exportedTestData/auth_export/accounts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/exportedTestData/auth_export/accounts.json b/tests/integration/exportedTestData/auth_export/accounts.json index f932a8f3b..df84363a9 100644 --- a/tests/integration/exportedTestData/auth_export/accounts.json +++ b/tests/integration/exportedTestData/auth_export/accounts.json @@ -1 +1 @@ -{"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"05lcy6YQrPvPRvVPlZFbCA0O81TF","lastLoginAt":"1682192783216","emailVerified":true,"email":"testadmin@example.com","salt":"fakeSaltQ0CeYd5UyEmOq5MWLcnP","passwordHash":"fakeHash:salt=fakeSaltQ0CeYd5UyEmOq5MWLcnP:password=password","passwordUpdatedAt":1682192769498,"validSince":"1682192769","createdAt":"1682192575545","providerUserInfo":[{"providerId":"password","email":"testadmin@example.com","federatedId":"testadmin@example.com","rawId":"testadmin@example.com","displayName":"","photoUrl":""}],"lastRefreshAt":"2023-04-22T19:46:23.216Z","customAttributes":"{\"role\":\"admin\"}","displayName":"","photoUrl":""},{"localId":"PbB7tQy18F9bQXfI3AonVmFfQU1B","createdAt":"1647962671353","lastLoginAt":"1649530941158","displayName":"test1","photoUrl":"","passwordHash":"fakeHash:salt=fakeSaltuknPVwAkolkrDbQLJkUa:password=password","salt":"fakeSaltuknPVwAkolkrDbQLJkUa","passwordUpdatedAt":1682192348137,"providerUserInfo":[{"providerId":"password","email":"test@example.com","federatedId":"test@example.com","rawId":"test@example.com","displayName":"test1","photoUrl":""}],"validSince":"1682192348","email":"test@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"},{"localId":"VBN6dg70PGsupNvayJ2TPHPgydHz","createdAt":"1647962690530","lastLoginAt":"1647962870753","displayName":"test2","photoUrl":"","passwordHash":"fakeHash:salt=fakeSalt2x7l7erotVwSgZtSrvE4:password=password","salt":"fakeSalt2x7l7erotVwSgZtSrvE4","passwordUpdatedAt":1682192348137,"providerUserInfo":[{"providerId":"password","email":"test3@example.com","federatedId":"test3@example.com","rawId":"test3@example.com","displayName":"test2","photoUrl":""}],"validSince":"1682192348","email":"test3@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"},{"localId":"d6ZFKTVH8i4hglyv42wz8QDaKKxw","createdAt":"1647962684429","lastLoginAt":"1647962684429","displayName":"test3","photoUrl":"","passwordHash":"fakeHash:salt=fakeSalt9WTUIwt7hSmUtHEWukrL:password=password","salt":"fakeSalt9WTUIwt7hSmUtHEWukrL","passwordUpdatedAt":1682192348138,"providerUserInfo":[{"providerId":"password","email":"test2@example.com","federatedId":"test2@example.com","rawId":"test2@example.com","displayName":"test3","photoUrl":""}],"validSince":"1682192348","email":"test2@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"},{"localId":"jLPye8OfwlzAEGO6h10hs5mmVIDE","createdAt":"1647962700251","lastLoginAt":"1647962870743","displayName":"test4","photoUrl":"","passwordHash":"fakeHash:salt=fakeSaltExpNl9RTLBTTOfrDMtdM:password=password","salt":"fakeSaltExpNl9RTLBTTOfrDMtdM","passwordUpdatedAt":1682192348138,"providerUserInfo":[{"providerId":"password","email":"test4@example.com","federatedId":"test4@example.com","rawId":"test4@example.com","displayName":"test4","photoUrl":""}],"validSince":"1682192348","email":"test4@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"}]} \ No newline at end of file +{"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"05lcy6YQrPvPRvVPlZFbCA0O81TF","lastLoginAt":"1682192783216","emailVerified":true,"email":"testadmin@example.com","salt":"fakeSaltQ0CeYd5UyEmOq5MWLcnP","passwordHash":"fakeHash:salt=fakeSaltQ0CeYd5UyEmOq5MWLcnP:password=password","passwordUpdatedAt":1682192769498,"validSince":"1682192769","createdAt":"1682192575545","providerUserInfo":[{"providerId":"password","email":"testadmin@example.com","federatedId":"testadmin@example.com","rawId":"testadmin@example.com","displayName":"","photoUrl":""}],"lastRefreshAt":"2023-04-22T19:46:23.216Z","customAttributes":"{\"role\":\"admin\"}","displayName":"","photoUrl":""},{"localId":"PbB7tQy18F9bQXfI3AonVmFfQU1B","createdAt":"1647962671353","lastLoginAt":"1649530941158","displayName":"test1","photoUrl":"","passwordHash":"fakeHash:salt=fakeSaltuknPVwAkolkrDbQLJkUa:password=password","salt":"fakeSaltuknPVwAkolkrDbQLJkUa","passwordUpdatedAt":1682192348137,"providerUserInfo":[{"providerId":"password","email":"test@example.com","federatedId":"test@example.com","rawId":"test@example.com","displayName":"test1","photoUrl":""}],"validSince":"1682192348","email":"test@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"},{"localId":"VBN6dg70PGsupNvayJ2TPHPgydHz","createdAt":"1647962690530","lastLoginAt":"1647962870753","displayName":"test2","photoUrl":"","passwordHash":"fakeHash:salt=fakeSalt2x7l7erotVwSgZtSrvE4:password=password","salt":"fakeSalt2x7l7erotVwSgZtSrvE4","passwordUpdatedAt":1682192348137,"providerUserInfo":[{"providerId":"password","email":"test3@example.com","federatedId":"test3@example.com","rawId":"test3@example.com","displayName":"test2","photoUrl":""}],"validSince":"1682192348","email":"test3@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"},{"localId":"d6ZFKTVH8i4hglyv42wz8QDaKKxw","createdAt":"1647962684429","lastLoginAt":"1647962684429","displayName":"test3","photoUrl":"","passwordHash":"fakeHash:salt=fakeSalt9WTUIwt7hSmUtHEWukrL:password=password","salt":"fakeSalt9WTUIwt7hSmUtHEWukrL","passwordUpdatedAt":1682192348138,"providerUserInfo":[{"providerId":"password","email":"test2@example.com","federatedId":"test2@example.com","rawId":"test2@example.com","displayName":"test3","photoUrl":""}],"validSince":"1682192348","email":"test2@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"},{"localId":"jLPye8OfwlzAEGO6h10hs5mmVIDE","createdAt":"1647962700251","lastLoginAt":"1647962870743","displayName":"test4","photoUrl":"","passwordHash":"fakeHash:salt=fakeSaltExpNl9RTLBTTOfrDMtdM:password=password","salt":"fakeSaltExpNl9RTLBTTOfrDMtdM","passwordUpdatedAt":1682192348138,"providerUserInfo":[{"providerId":"password","email":"test4@example.com","federatedId":"test4@example.com","rawId":"test4@example.com","displayName":"test4","photoUrl":""}],"validSince":"1682192348","email":"test4@example.com","emailVerified":false,"disabled":false,"customAttributes":"{\"role\":\"user\"}"},{"localId":"05lcy6YQrPvPRvVPlZFbCA0O81TM","createdAt":"1647962700251","lastLoginAt":"1647962870743","displayName":"verified","photoUrl":"","passwordHash":"fakeHash:salt=fakeSaltExpNl9RTLBTTOfrDMtdM:password=password","salt":"fakeSaltExpNl9RTLBTTOfrDMtdM","passwordUpdatedAt":1682192348138,"providerUserInfo":[{"providerId":"password","email":"verifieduser@example.com","federatedId":"verifieduser@example.com","rawId":"verifieduser@example.com","displayName":"verified","photoUrl":""}],"validSince":"1682192348","email":"verifieduser@example.com","emailVerified":true,"disabled":false,"customAttributes":"{\"role\":\"user\"}"}]} \ No newline at end of file