Browse Source

add tests for importing multiple records, fix other confirmation tests

Trent Larson 3 months ago
parent
commit
c5c687a9c5
  1. 12
      src/components/TopMessage.vue
  2. 2
      src/libs/endorserServer.ts
  3. 12
      src/views/AccountViewView.vue
  4. 1
      src/views/ClaimView.vue
  5. 48
      src/views/ConfirmGiftView.vue
  6. 8
      src/views/ContactImportView.vue
  7. 20
      src/views/ContactsView.vue
  8. 5
      src/views/HelpView.vue
  9. 75
      test-playwright/40-add-contact.spec.ts

12
src/components/TopMessage.vue

@ -1,5 +1,15 @@
<template>
<div class="text-center text-red-500">{{ message }}</div>
<div class="absolute right-5 top-3">
<span class="align-center text-red-500 mr-2">{{ message }}</span>
<span class="ml-2">
<router-link
:to="{ name: 'help' }"
class="text-xs uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-1 rounded-md ml-1"
>
Help
</router-link>
</span>
</div>
</template>
<script lang="ts">

2
src/libs/endorserServer.ts

@ -85,6 +85,7 @@ export interface GiveSummaryRecord {
fulfillsPlanHandleId: string;
handleId: string;
issuedAt: string;
issuerDid: string;
jwtId: string;
recipientDid: string;
unit: string;
@ -98,6 +99,7 @@ export interface OfferSummaryRecord {
fullClaim: OfferVerifiableCredential;
fulfillsPlanHandleId: string;
handleId: string;
issuerDid: string;
jwtId: string;
nonAmountGivenConfirmed: number;
objectDescription: string;

12
src/views/AccountViewView.vue

@ -22,18 +22,6 @@
<span />
</div>
<div class="flex justify-between py-2">
<span />
<span>
<router-link
:to="{ name: 'help' }"
class="text-xs uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-1 rounded-md ml-1"
>
Help
</router-link>
</span>
</div>
<!-- ID notice -->
<div
v-if="!activeDid"

1
src/views/ClaimView.vue

@ -176,6 +176,7 @@
v-if="libsUtil.isGiveAction(veriClaim)"
:to="'/confirm-gift/' + encodeURIComponent(veriClaim.id)"
class="col-span-1 text-blue-500"
data-testId="confirmGiftLink"
>
Details...
</router-link>

48
src/views/ConfirmGiftView.vue

@ -1,5 +1,6 @@
<template>
<QuickNav />
<TopMessage />
<!-- CONTENT -->
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
<!-- Breadcrumb -->
@ -148,10 +149,10 @@
<span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
<span v-else-if="totalConfirmers() === 1">
One person has confirmed this.
One person confirmed this.
</span>
<span v-else>
{{ totalConfirmers() }} people have confirmed this.
{{ totalConfirmers() }} people confirmed this.
</span>
<div v-if="totalConfirmers() > 0">
@ -170,10 +171,10 @@
"
>
<!-- Only show if this person has links to confirmers (below). -->
Nobody that you know has issued or confirmed this claim.
Nobody that you know issued or confirmed this claim.
</div>
<div v-if="confirmerIdList.length > 0">
The following people have issued or confirmed this claim.
The following people issued or confirmed this claim.
<ul class="ml-4">
<li
v-for="confirmerId in confirmerIdList"
@ -205,7 +206,7 @@
<!--
Never need to show this message:
"Nobody that you know can see someone who has confirmed this claim."
"Nobody that you know can see someone who confirmed this claim."
If there is nobody in the confirmerIdList then we'll show the combined "nobody" message.
If there is somebody in the confirmerIdList then that's all they need to show.
@ -213,7 +214,7 @@
<!-- Now show anyone linked to confirmers. -->
<div v-if="confsVisibleToIdList.length > 0">
The following people can connect you with people who have issued or
The following people can connect you with people who issued or
confirmed this claim.
<ul class="ml-4">
<li
@ -249,10 +250,11 @@
<!-- explain if user cannot confirm -->
<!-- Note that these conditions are mirrored in userCanConfirm(). -->
<div v-if="confirmerIdList.includes(activeDid)">
You have confirmed this claim.
<div v-if="!isRegistered">
You cannot confirm this because you are not registered. Find someone
to register you, maybe on the Help page.
</div>
<div v-else-if="giveDetails.agentDid == activeDid">
<div v-else-if="giveDetails.issuerDid == activeDid">
You cannot confirm this because you issued this claim, so you already
count as confirming it.
</div>
@ -410,13 +412,14 @@ import { Account } from "@/db/tables/accounts";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import * as serverUtil from "@/libs/endorserServer";
import { displayAmount } from "@/libs/endorserServer";
import {displayAmount, GiveSummaryRecord} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { isGiveAction } from "@/libs/util";
import TopMessage from "@/components/TopMessage.vue";
@Component({
methods: { displayAmount },
components: { QuickNav },
components: { TopMessage, QuickNav },
})
export default class ClaimView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
@ -430,7 +433,7 @@ export default class ClaimView extends Vue {
confirmerIdList: string[] = []; // list of DIDs that have confirmed this claim excluding the issuer
confsVisibleErrorMessage = "";
confsVisibleToIdList: string[] = []; // list of DIDs that can see any confirmer
giveDetails = null;
giveDetails?: GiveSummaryRecord;
giverName = "";
issuerName = "";
isLoading = false;
@ -453,7 +456,7 @@ export default class ClaimView extends Vue {
this.confirmerIdList = [];
this.confsVisibleErrorMessage = "";
this.confsVisibleToIdList = [];
this.giveDetails = null;
this.giveDetails = undefined;
this.isRegistered = false;
this.numConfsNotVisible = 0;
this.urlForNewGive = "";
@ -605,6 +608,12 @@ export default class ClaimView extends Vue {
},
3000,
);
return;
}
// the logic already stops earlier if the claim doesn't exist but this helps with typechecking
if (!this.giveDetails) {
return;
}
this.urlForNewGive = "/gifted-details?";
@ -645,7 +654,8 @@ export default class ClaimView extends Vue {
this.giveDetails.fulfillsHandleId
) {
this.urlForNewGive +=
"&offerId=" + encodeURIComponent(this.giveDetails.fulfillsHandleId);
"&offerId=" +
encodeURIComponent(this.giveDetails?.fulfillsHandleId as string);
}
if (this.giveDetails.fulfillsPlanHandleId) {
this.urlForNewGive +=
@ -666,9 +676,11 @@ export default class ClaimView extends Vue {
const resultList1 = response.data.result || [];
//const publicUrls = resultList.publicUrls || [];
delete resultList1.publicUrls;
// remove any hidden DIDs
const resultList2 = R.reject(serverUtil.isHiddenDid, resultList1);
// remove confirmations by this user
const resultList3 = R.reject(
(did: string) => did === this.giveDetails.agentDid,
(did: string) => did === this.giveDetails?.issuerDid,
resultList2,
);
this.confirmerIdList = resultList3;
@ -814,11 +826,11 @@ export default class ClaimView extends Vue {
group: "alert",
type: "info",
title: "Already Confirmed",
text: "You have already confirmed this claim.",
text: "You already confirmed this claim.",
},
3000,
);
} else if (this.giveDetails.agentDid == this.activeDid) {
} else if (this.giveDetails?.issuerDid == this.activeDid) {
this.$notify(
{
group: "alert",
@ -828,7 +840,7 @@ export default class ClaimView extends Vue {
},
3000,
);
} else if (serverUtil.containsHiddenDid(this.giveDetails.fullClaim)) {
} else if (serverUtil.containsHiddenDid(this.giveDetails?.fullClaim)) {
this.$notify(
{
group: "alert",

8
src/views/ContactImportView.vue

@ -21,8 +21,12 @@
Contacts.
</span>
<div v-if="sameCount > 0">
{{ sameCount }} contact{{ sameCount == 1 ? "" : "s" }} are the same as
existing contacts.
<span v-if="sameCount == 1"
>One contact is the same as an existing contact</span
>
<span v-else
>{{ sameCount }} contacts are the same as existing contacts</span
>
</div>
<!-- Results List -->

20
src/views/ContactsView.vue

@ -1,5 +1,7 @@
<template>
<QuickNav selected="Contacts"></QuickNav>
<QuickNav selected="Contacts" />
<TopMessage />
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
<!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
@ -41,7 +43,7 @@
</button>
</div>
<div class="flex justify-between">
<div class="flex justify-between" v-if="contacts.length > 0">
<div class="w-full text-left">
<input
type="checkbox"
@ -53,6 +55,7 @@
: (contactsSelected = contacts.map((contact) => contact.did))
"
class="align-middle ml-2 h-6 w-6"
data-testId="contactCheckAllTop"
/>
<button
href=""
@ -64,8 +67,9 @@
"
@click="copySelectedContacts()"
v-if="!showGiveNumbers"
data-testId="copySelectedContactsButtonTop"
>
Copy Selected Contacts
Copy Selections
</button>
</div>
@ -117,6 +121,7 @@
class="border-b border-slate-300 pt-1 pb-1"
v-for="contact in filteredContacts()"
:key="contact.did"
data-testId="contactListItem"
>
<div class="grow overflow-hidden">
<div class="flex items-center">
@ -140,6 +145,7 @@
: contactsSelected.push(contact.did)
"
class="ml-2 h-6 w-6"
data-testId="contactCheckOne"
/>
<h2 class="text-base font-semibold ml-2">
@ -226,7 +232,7 @@
</ul>
<p v-else>There are no contacts.</p>
<div class="mt-2 w-full text-left">
<div class="mt-2 w-full text-left" v-if="contacts.length > 0">
<input
type="checkbox"
v-if="!showGiveNumbers"
@ -237,6 +243,7 @@
: (contactsSelected = contacts.map((contact) => contact.did))
"
class="align-middle ml-2 h-6 w-6"
data-testId="contactCheckAllBottom"
/>
<button
href=""
@ -249,7 +256,7 @@
@click="copySelectedContacts()"
v-if="!showGiveNumbers"
>
Copy Selected Contacts
Copy Selections
</button>
</div>
@ -300,9 +307,10 @@ import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue";
import GiftedDialog from "@/components/GiftedDialog.vue";
import OfferDialog from "@/components/OfferDialog.vue";
import TopMessage from "@/components/TopMessage.vue";
@Component({
components: { GiftedDialog, EntityIcon, OfferDialog, QuickNav },
components: {TopMessage, GiftedDialog, EntityIcon, OfferDialog, QuickNav },
})
export default class ContactsView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;

5
src/views/HelpView.vue

@ -54,8 +54,9 @@
<h2 class="text-xl font-semibold">How do I get started?</h2>
<p>
You need someone to register you, like the person who told you
about this app, on the Contacts
<fa icon="users" class="fa-fw" /> page. After they register you, you can
about this app, on the Contacts <fa icon="users" class="fa-fw" /> page.
If you heard about this from our outreach, feel free to contact us (below) for a chat.
After someone registers you, you can
select any contact on the home page (or "anonymous") and record your
appreciation for... whatever. The main goal is to record what people
have given you, to grow giving economies. You can also record your own

75
test-playwright/40-add-contact.spec.ts

@ -21,26 +21,25 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
const finalTitle = standardTitle + finalRandomString;
// Contact name
const contactName = 'Contact #000';
const contactName = 'Contact #111';
// Import user 01
await importUser(page, '01');
// Add new contact 00
// Add new contact
await page.goto('./contacts');
await page.getByPlaceholder('URL or DID, Name, Public Key').fill('did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F, User #000');
await page.locator('button > svg.fa-plus').click();
await expect(page.locator('div[role="alert"]')).toBeVisible();
// Why doesn't the alert box come up every time?
// await page.locator('div[role="alert"] button:has-text("Yes")').click();
await page.locator('div[role="alert"] button:has-text("Yes")').click();
// Verify added contact
await expect(page.locator('li.border-b')).toContainText('User #000');
// Rename contact
await page.locator('li.border-b div div > a[title="See more about this person"]').click();
await page.locator('h2 > button[title="Edit"]').click();
await page.locator('h2 > button > svg.fa-pen').click();
await expect(page.locator('div.dialog-overlay > div.dialog').filter({ hasText: 'Edit Name' })).toBeVisible();
await page.getByPlaceholder('Name', { exact: true }).fill(contactName);
await page.locator('.dialog > .flex > button').first().click();
@ -76,11 +75,73 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
await page.locator('li').filter({ hasText: finalTitle }).locator('a').click();
// Confirm gift as user 00
await page.getByTestId('confirmGiftLink').click();
await page.getByRole('button', { name: 'Confirm' }).click();
await page.getByRole('button', { name: 'Yes' }).click();
await expect(page.getByText('Confirmation submitted.')).toBeVisible();
// Refresh claim page, Confirm button should be hidden
// Refresh claim page, Confirm button should throw an alert because they already confirmed
await page.reload();
await expect(page.getByRole('button', { name: 'Confirm' })).toBeHidden();
await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.locator('div[role="alert"]')).toBeVisible();
});
test('Add contact, copy details, delete, and import various ways', async ({ page, context }) => {
await importUser(page, '00');
// Add new contact
await page.goto('./contacts');
await page.getByPlaceholder('URL or DID, Name, Public Key').fill('did:ethr:0x111d15564f824D56C7a07b913aA7aDd03382aA39, User #111');
await page.locator('button > svg.fa-plus').click();
await expect(page.locator('div[role="alert"]')).toBeVisible();
await page.locator('div[role="alert"] button:has-text("No")').click();
await page.locator('div[role="alert"] button > svg.fa-xmark').click();
// wait for the alert to disappear
await expect(page.locator('div[role="alert"]')).toBeHidden();
// Add another new contact
await page.getByPlaceholder('URL or DID, Name, Public Key').fill('did:ethr:0x222BB77E6Ff3774d34c751f3c1260866357B677b, User #222, asdf1234');
await page.locator('button > svg.fa-plus').click();
await expect(page.locator('div[role="alert"]')).toBeVisible();
await page.locator('div[role="alert"] button:has-text("No")').click();
await page.locator('div[role="alert"] button > svg.fa-xmark').click();
await expect(page.locator('div[role="alert"]')).toBeHidden();
await expect(page.getByTestId('contactListItem')).toHaveCount(2);
//// Copy contact details, export them, remove them, and paste to add them
// Copy contact details
await page.getByTestId('contactCheckAllTop').click();
await page.getByTestId('copySelectedContactsButtonTop').click();
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
// 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 contact details on the second contact
await page.getByTestId('contactListItem').nth(1).locator('a').click();
// remove contact
await page.locator('button > svg.fa-trash-can').click();
await page.locator('div[role="alert"] button:has-text("Yes")').click();
// for some reason, .isHidden() (without expect) doesn't work
await expect(page.locator('div[role="alert"] button:has-text("Yes")')).toBeHidden();
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
// go to the contacts page and paste the copied contact details
await page.goto('./contacts');
// check that there are fewer contacts
await expect(page.getByTestId('contactListItem')).toHaveCount(1);
const contactData = 'Paste this: [{ "did": "did:ethr:0x111d15564f824D56C7a07b913aA7aDd03382aA39", "name": "User #111" }, { "did": "did:ethr:0x222BB77E6Ff3774d34c751f3c1260866357B677b", "name": "User #222", "publicKeyBase64": "asdf1234"}] '
await page.getByPlaceholder('URL or DID, Name, Public Key').fill(contactData);
await page.locator('button > svg.fa-plus').click();
// we're on the contact-import page
await expect(page.locator('li', { hasText: 'New' })).toHaveCount(1);
await expect(page.locator('span').filter({ hasText: 'the same as' })).toBeVisible();
await page.locator('button', { hasText: 'Import' }).click();
// check that there are more contacts
await expect(page.getByTestId('contactListItem')).toHaveCount(2);
});

Loading…
Cancel
Save