From 55abb5d9254b20547e93c1d806f77dbf9ac55350 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Wed, 1 Jan 2025 20:08:21 -0700 Subject: [PATCH 01/24] add test that copies contact-import JWT to clipboard and imports from it --- CHANGELOG.md | 2 +- src/views/ContactsView.vue | 8 ++-- test-playwright/05-invite.spec.ts | 3 +- test-playwright/40-add-contact.spec.ts | 62 +++++++++++++++++++++++--- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91c189a..3c10f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.45] - 2025.01.01 - 65402dc68ce69ccc6cb9aa8d2e7a9249bf4298e0 ### Fixed -- Previous project links stayed when following a link +- Previous project links stayed when following a link. ## [0.3.44] - 2024.12.31 - 694b22987b05482e4527c2478bbe15e6b6f3b532 diff --git a/src/views/ContactsView.vue b/src/views/ContactsView.vue index a69eba1..6f91815 100644 --- a/src/views/ContactsView.vue +++ b/src/views/ContactsView.vue @@ -1269,10 +1269,10 @@ export default class ContactsView extends Vue { const selectedContacts = this.contacts.filter((c) => this.contactsSelected.includes(c.did), ); - console.log( - "Array of selected contacts:", - JSON.stringify(selectedContacts), - ); + // console.log( + // "Array of selected contacts:", + // JSON.stringify(selectedContacts), + // ); const contactsJwt = await createEndorserJwtForDid(this.activeDid, { contacts: selectedContacts, }); diff --git a/test-playwright/05-invite.spec.ts b/test-playwright/05-invite.spec.ts index 37b1d49..114bffc 100644 --- a/test-playwright/05-invite.spec.ts +++ b/test-playwright/05-invite.spec.ts @@ -2,8 +2,6 @@ import { test, expect } from '@playwright/test'; import { deleteContact, generateNewEthrUser, generateRandomString, importUser, switchToUser } from './testUtils'; test('Check User 0 can invite someone', async ({ page }) => { - const newDid = await generateNewEthrUser(page); - await importUser(page, '00'); await page.goto('./invite-one'); await page.locator('button > svg.fa-plus').click(); @@ -23,6 +21,7 @@ test('Check User 0 can invite someone', async ({ page }) => { expect(inviteLink).not.toBeNull(); // become the new user and accept the invite + const newDid = await generateNewEthrUser(page); await switchToUser(page, newDid); await page.goto(inviteLink as string); await page.getByPlaceholder('Name', { exact: true }).fill(`My pal User #0`); diff --git a/test-playwright/40-add-contact.spec.ts b/test-playwright/40-add-contact.spec.ts index 0826700..8fa791e 100644 --- a/test-playwright/40-add-contact.spec.ts +++ b/test-playwright/40-add-contact.spec.ts @@ -145,10 +145,7 @@ test('Add contact, copy details, delete, and import from paste & from file', asy await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert await expect(page.locator('div[role="alert"]')).toBeHidden(); // I would prefer to copy from the clipboard, but the recommended approaches don't work. - // this seems to fail in non-chromium browsers - //await context.grantPermissions(['clipboard-read', 'clipboard-write']); - // this seems to fail in chromium (at least) where clipboard is undefined - //const contactData = await navigator.clipboard.readText(); + // See a different clipboard solution below. // see contact details on the second contact await page.getByTestId('contactListItem').nth(1).locator('a').click(); @@ -185,7 +182,6 @@ test('Add contact, copy details, delete, and import from paste & from file', asy await page.goto('./account'); await page.getByRole('heading', { name: 'Advanced' }).click(); const fileSelect = await page.locator('input[type="file"]') - //fileSelect.click(); fileSelect.setInputFiles('./test-playwright/exported-data.json'); await page.locator('button', { hasText: 'Import Only Contacts' }).click(); // we're on the contact-import page @@ -199,3 +195,59 @@ test('Add contact, copy details, delete, and import from paste & from file', asy // But it should only show that one, for User #000. }); + +test('Copy contact to clipboard, then import ', async ({ page, context }) => { + await importUser(page, '00'); + + await page.goto('./account'); + await page.getByRole('heading', { name: 'Advanced' }).click(); + const fileSelect = await page.locator('input[type="file"]') + fileSelect.setInputFiles('./test-playwright/exported-data.json'); + await page.locator('button', { hasText: 'Import Only Contacts' }).click(); + // we're on the contact-import page + await expect(page.getByRole('heading', { name: "Contact Import" })).toBeVisible(); + await page.locator('button', { hasText: 'Import' }).click(); + + await page.goto('./contacts'); + // Copy contact details + await page.getByTestId('contactCheckAllTop').click(); + + // // There's a crazy amount of overlap in all the userAgent values. Ug. + // const agent = await page.evaluate(() => { + // return navigator.userAgent; + // }); + // console.log("agent: ", agent); + + const isFirefox = await page.evaluate(() => { + return navigator.userAgent.includes('Firefox'); + }); + if (isFirefox) { + // Firefox doesn't grant permissions like this but it works anyway. + } else { + await context.grantPermissions(['clipboard-read']); + } + + const isWebkit = await page.evaluate(() => { + return navigator.userAgent.includes('Macintosh') || navigator.userAgent.includes('iPhone'); + }); + if (isWebkit) { + console.log("Haven't found a way to access clipboard text in Webkit. Skipping."); + return; + } + + console.log("Running test that copies contact details to clipboard."); + await page.getByTestId('copySelectedContactsButtonTop').click(); + const clipboardText = await page.evaluate(async () => { + return navigator.clipboard.readText(); + }); + const PATH_PART = "http://localhost:8080/contact-import/"; + expect(clipboardText).toContain(PATH_PART); + + await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert + await expect(page.locator('div[role="alert"]')).toBeHidden(); + + await page.goto(clipboardText); + // we're on the contact-import page + await expect(page.getByRole('heading', { name: "Contact Import" })).toBeVisible(); + await expect(page.locator('span', { hasText: '4 contacts are the same' })).toBeVisible(); +}); From 7db5b9875b2fd5123a6c05aa9d632ca9f85abee8 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Fri, 3 Jan 2025 09:47:42 -0700 Subject: [PATCH 02/24] fix error where visibility was set on all imported contacts even if not selected (and specify more types) --- src/views/ContactImportView.vue | 48 ++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/views/ContactImportView.vue b/src/views/ContactImportView.vue index 9946e28..198c7e1 100644 --- a/src/views/ContactImportView.vue +++ b/src/views/ContactImportView.vue @@ -124,7 +124,10 @@ export default class ContactImportView extends Vue { contactsSelected: Array = []; // whether each contact in contactsImporting is selected contactDifferences: Record< string, - Record + Record< + string, + { new: string | boolean | undefined; old: string | boolean | undefined } + > > = {}; // for existing contacts, it shows the difference between imported and existing contacts for each key importing = false; makeVisible = true; @@ -170,12 +173,19 @@ export default class ContactImportView extends Vue { if (existingContact) { this.contactsExisting[contactIn.did] = existingContact; - const differences: Record = {}; + const differences: Record< + string, + { + new: string | boolean | undefined; + old: string | boolean | undefined; + } + > = {}; Object.keys(contactIn).forEach((key) => { - if (contactIn[key] !== existingContact[key]) { + // eslint-disable-next-line prettier/prettier + if (contactIn[key as keyof Contact] !== existingContact[key as keyof Contact]) { differences[key] = { - old: existingContact[key], - new: contactIn[key], + old: existingContact[key as keyof Contact], + new: contactIn[key as keyof Contact], }; } }); @@ -211,22 +221,24 @@ export default class ContactImportView extends Vue { if (this.makeVisible) { const failedVisibileToContacts = []; for (let i = 0; i < this.contactsImporting.length; i++) { - const contact = this.contactsImporting[i]; - if (contact) { - const visResult = await setVisibilityUtil( - this.activeDid, - this.apiServer, - this.axios, - db, - contact, - true, - ); - if (!visResult.success) { - failedVisibileToContacts.push(contact); + if (this.contactsSelected[i]) { + const contact = this.contactsImporting[i]; + if (contact) { + const visResult = await setVisibilityUtil( + this.activeDid, + this.apiServer, + this.axios, + db, + contact, + true, + ); + if (!visResult.success) { + failedVisibileToContacts.push(contact); + } } } } - if (failedVisibileToContacts.length) { + if (failedVisibileToContacts.length > 0) { this.$notify( { group: "alert", From 15e00f9be01f386416eae8a8b2bbfaaae02219d9 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Fri, 3 Jan 2025 09:48:33 -0700 Subject: [PATCH 03/24] fix verbiage when looking at new offers --- src/views/NewActivityView.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/views/NewActivityView.vue b/src/views/NewActivityView.vue index 81f6414..e8fce16 100644 --- a/src/views/NewActivityView.vue +++ b/src/views/NewActivityView.vue @@ -61,7 +61,7 @@ > - +