+
{{ numNewOffersToUser }}
new offer{{ numNewOffersToUser === 1 ? "" : "s" }} to you
diff --git a/src/views/NewActivityView.vue b/src/views/NewActivityView.vue
index 61f85a45f..9f3ecc6e4 100644
--- a/src/views/NewActivityView.vue
+++ b/src/views/NewActivityView.vue
@@ -25,18 +25,25 @@
:icon="showOffersDetails ? 'chevron-down' : 'chevron-right'"
class="cursor-pointer ml-4 text-lg"
@click="expandOffersToUserAndMarkRead()"
+ data-testid="showOffersToUser"
/>
- -
+
-
{{
didInfo(offer.offeredByDid, activeDid, allMyDids, allContacts)
}}
offers
- {{ offer.objectDescription }}
- {{ offer.objectDescription && offer.amount ? ", and " : "" }}
+ {{
+ offer.objectDescription
+ }}{{ offer.objectDescription && offer.amount ? ", and " : "" }}
{{
displayAmount(offer.unit, offer.amount)
}}
@@ -67,7 +74,12 @@ import GiftedDialog from "@/components/GiftedDialog.vue";
import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue";
import { NotificationIface } from "@/constants/app";
-import { accountsDB, db, retrieveSettingsForActiveAccount, updateAccountSettings } from "@/db/index";
+import {
+ accountsDB,
+ db,
+ retrieveSettingsForActiveAccount,
+ updateAccountSettings,
+} from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import {
didInfo,
@@ -151,7 +163,9 @@ export default class NewActivityView extends Vue {
}
async markOffersAsReadStartingWith(jwtId: string) {
- const index = this.newOffersToUser.findIndex(offer => offer.jwtId === jwtId);
+ const index = this.newOffersToUser.findIndex(
+ (offer) => offer.jwtId === jwtId,
+ );
if (index !== -1 && index < this.newOffersToUser.length - 1) {
// Set to the next offer's jwtId
await updateAccountSettings(this.activeDid, {
diff --git a/test-playwright/60-new-activity.spec.ts b/test-playwright/60-new-activity.spec.ts
new file mode 100644
index 000000000..86e05551e
--- /dev/null
+++ b/test-playwright/60-new-activity.spec.ts
@@ -0,0 +1,79 @@
+import { test, expect } from '@playwright/test';
+import { importUser, generateNewEthrUser, switchToUser } from './testUtils';
+
+test('New offers for another user', async ({ page }) => {
+ const user01Did = await generateNewEthrUser(page);
+ await page.goto('./');
+ expect(page.getByTestId('newDirectOffersActivityNumber')).toBeHidden();
+
+ await importUser(page, '00');
+ await page.goto('./contacts');
+ await page.getByPlaceholder('URL or DID, Name, Public Key').fill(user01Did + ', A Friend');
+ await page.locator('button > svg.fa-plus').click();
+ await expect(page.locator('div[role="alert"] span:has-text("Contact Added")')).toBeVisible();
+ await page.locator('div[role="alert"] button:has-text("No")').click(); // don't register
+ await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss info alert
+ await expect(page.locator('div[role="alert"] button > svg.fa-xmark')).toBeHidden(); // ensure alert is gone
+
+ // show buttons to make offers directly to people
+ await page.getByRole('button').filter({ hasText: /Show Given Hours/i }).click();
+
+ // make an offer directly to user 1
+ // Generate a random string of 3 characters, skipping the "0." at the beginning
+ const randomString1 = Math.random().toString(36).substring(2, 5);
+ await page.getByTestId('offerButton').click();
+ await page.getByTestId('inputDescription').fill(`help of ${randomString1} from #000`);
+ await page.getByTestId('inputOfferAmount').fill('1');
+ await page.getByRole('button', { name: 'Sign & Send' }).click();
+ await expect(page.getByText('That offer was recorded.')).toBeVisible();
+ await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss info alert
+ await expect(page.locator('div[role="alert"] button > svg.fa-xmark')).toBeHidden(); // ensure alert is gone
+
+ // make another offer to user 1
+ const randomString2 = Math.random().toString(36).substring(2, 5);
+ await page.getByTestId('offerButton').click();
+ await page.getByTestId('inputDescription').fill(`help of ${randomString2} from #000`);
+ await page.getByTestId('inputOfferAmount').fill('3');
+ await page.getByRole('button', { name: 'Sign & Send' }).click();
+ await expect(page.getByText('That offer was recorded.')).toBeVisible();
+ await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss info alert
+ await expect(page.locator('div[role="alert"] button > svg.fa-xmark')).toBeHidden(); // ensure alert is gone
+
+ // as user 1, go to the home page and check that two offers are shown as new
+ await switchToUser(page, user01Did);
+ await page.goto('./');
+ await page.getByTestId('closeOnboardingAndFinish').click();
+ let offerNumElem = page.getByTestId('newDirectOffersActivityNumber');
+ await expect(offerNumElem).toHaveText('2');
+ await offerNumElem.click();
+
+ await expect(page.getByText('New Offers To You')).toBeVisible();
+ await page.getByTestId('showOffersToUser').click();
+ // note that they show in reverse chronologicalorder
+ await expect(page.getByText(`help of ${randomString2} from #000`)).toBeVisible();
+ await expect(page.getByText(`help of ${randomString1} from #000`)).toBeVisible();
+
+ // click on the latest offer to keep it as "unread"
+ await page.hover(`li:has-text("help of ${randomString2} from #000")`);
+ // await page.locator('li').filter({ hasText: `help of ${randomString2} from #000` }).click();
+ // await page.locator('div').filter({ hasText: /keep all above/ }).click();
+ // now find the "Click to keep all above as new offers" after that list item and click it
+ const liElem = page.locator('li').filter({ hasText: `help of ${randomString2} from #000` });
+ await liElem.hover();
+ const keepAboveAsNew = liElem.locator('div').filter({ hasText: /keep all above/ });
+ await keepAboveAsNew.click();
+
+ // now see that only one offer is shown as new
+ await page.goto('./');
+ offerNumElem = page.getByTestId('newDirectOffersActivityNumber');
+ await expect(offerNumElem).toHaveText('1');
+ await offerNumElem.click();
+ await expect(page.getByText('New Offer To You')).toBeVisible();
+ await page.getByTestId('showOffersToUser').click();
+
+ // now see that no offers are shown as new
+ await page.goto('./');
+ // wait until the list with ID listLatestActivity has at least one visible item
+ await page.locator('#listLatestActivity li').first().waitFor({ state: 'visible' });
+ await expect(page.getByTestId('newDirectOffersActivityNumber')).toBeHidden();
+});
diff --git a/test-playwright/testUtils.ts b/test-playwright/testUtils.ts
index d6e0a447c..8e5f0164a 100644
--- a/test-playwright/testUtils.ts
+++ b/test-playwright/testUtils.ts
@@ -34,10 +34,12 @@ export async function importUser(page: Page, id?: string): Promise {
// This is to switch to someone already in the identity table. It doesn't include registration.
export async function switchToUser(page: Page, did: string): Promise {
- // await page.goto('./account');
- // await page.getByRole('heading', { name: 'Advanced' }).click();
- // await page.getByRole('link', { name: 'Switch Identifier' }).click();
- await page.goto('./identity-switcher');
+ // This is the direct approach but users have to tap on things so we'll do that instead.
+ //await page.goto('./identity-switcher');
+
+ await page.goto('./account');
+ await page.getByRole('heading', { name: 'Advanced' }).click();
+ await page.getByRole('link', { name: 'Switch Identifier' }).click();
const didElem = await page.locator(`code:has-text("${did}")`);
await didElem.isVisible();
await didElem.click();