Browse Source

fix list of offers (and some other lists), and add tests for offers

pull/123/head
Trent Larson 1 month ago
parent
commit
1fe540d5a8
  1. 7
      CHANGELOG.md
  2. 4
      playwright.config-local.ts
  3. 2
      src/components/OfferDialog.vue
  4. 17
      src/views/AccountViewView.vue
  5. 5
      src/views/ClaimView.vue
  6. 2
      src/views/ContactAmountsView.vue
  7. 2
      src/views/DiscoverView.vue
  8. 2
      src/views/NewEditProjectView.vue
  9. 1
      src/views/ProjectViewView.vue
  10. 8
      src/views/ProjectsView.vue
  11. 8
      src/views/SharedPhotoView.vue
  12. 2
      test-playwright/20-create-project.spec.ts
  13. 2
      test-playwright/30-record-gift.spec.ts
  14. 2
      test-playwright/40-add-contact.spec.ts
  15. 33
      test-playwright/50-record-offer.spec.ts
  16. 2
      test-playwright/testUtils.js

7
CHANGELOG.md

@ -6,7 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.3.16] - 2024.07.10 ## [0.3.18] - 2024.07.12
### Fixed
- List of offers wasn't showing.
## [0.3.17] - 2024.07.11 - cefa384ff1a2d922848c370640c096c529920fab
### Added ### Added
- Photos on more screens - Photos on more screens
### Fixed ### Fixed

4
playwright.config-local.ts

@ -72,9 +72,9 @@ export default defineConfig({
}, },
], ],
/* Configure global timeout */ /* Configure global timeout; default is 30000 milliseconds */
// the image upload will often not succeed at 5 seconds // the image upload will often not succeed at 5 seconds
//timeout: 7000, //timeout: 10000,
/* Run your local dev server before starting the tests */ /* Run your local dev server before starting the tests */
/** /**

2
src/components/OfferDialog.vue

@ -4,6 +4,7 @@
<h1 class="text-xl font-bold text-center mb-4">Offer Help</h1> <h1 class="text-xl font-bold text-center mb-4">Offer Help</h1>
<input <input
type="text" type="text"
data-testId="inputDescription"
class="block w-full rounded border border-slate-400 mb-2 px-3 py-2" class="block w-full rounded border border-slate-400 mb-2 px-3 py-2"
placeholder="Description, prerequisites, terms, etc." placeholder="Description, prerequisites, terms, etc."
v-model="description" v-model="description"
@ -23,6 +24,7 @@
<fa icon="chevron-left" /> <fa icon="chevron-left" />
</div> </div>
<input <input
data-testId="inputOfferAmount"
type="number" type="number"
class="w-full border border-r-0 border-slate-400 px-2 py-2 text-center" class="w-full border border-r-0 border-slate-400 px-2 py-2 text-center"
v-model="amountInput" v-model="amountInput"

17
src/views/AccountViewView.vue

@ -831,10 +831,16 @@ export default class AccountViewView extends Vue {
* Beware! I've seen where we never get to this point because "ready" never resolves. * Beware! I've seen where we never get to this point because "ready" never resolves.
*/ */
} catch (error) { } catch (error) {
// this can happen when running automated tests in dev mode because notifications don't work
console.error( console.error(
"Telling user to clear cache at page create because:", "Telling user to clear cache at page create because:",
error, error,
); );
// this sometimes gives different information on the error
console.error(
"Telling user to clear cache at page create because (error added): " +
error,
);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -1282,17 +1288,6 @@ export default class AccountViewView extends Vue {
} }
} catch (error) { } catch (error) {
this.handleRateLimitsError(error); this.handleRateLimitsError(error);
try {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
isRegistered: false,
});
this.isRegistered = false;
} catch (err) {
console.error("Got an error marking user not registered:", err);
// already set an error notification for the user
}
} }
this.loadingLimits = false; this.loadingLimits = false;

5
src/views/ClaimView.vue

@ -51,7 +51,10 @@
</div> </div>
<div> <div>
<fa icon="message" class="fa-fw text-slate-400" /> <fa icon="message" class="fa-fw text-slate-400" />
{{ veriClaim.claim?.description }} {{
veriClaim.claim?.description ||
veriClaim.claim?.itemOffered?.description
}}
</div> </div>
<div> <div>
<fa icon="user" class="fa-fw text-slate-400" /> <fa icon="user" class="fa-fw text-slate-400" />

2
src/views/ContactAmountsView.vue

@ -271,7 +271,7 @@ export default class ContactAmountssView extends Vue {
// Make the xhr request payload // Make the xhr request payload
const payload = JSON.stringify({ jwtEncoded: vcJwt }); const payload = JSON.stringify({ jwtEncoded: vcJwt });
const url = this.apiServer + "/api/v2/claim"; const url = this.apiServer + "/api/v2/claim";
const headers = getHeaders(this.activeDid) as AxiosRequestHeaders; const headers = (await getHeaders(this.activeDid)) as AxiosRequestHeaders;
try { try {
const resp = await this.axios.post(url, payload, { headers }); const resp = await this.axios.post(url, payload, { headers });

2
src/views/DiscoverView.vue

@ -265,6 +265,8 @@ export default class DiscoverView extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) { } catch (e: any) {
console.error("Error with feed load:", e); console.error("Error with feed load:", e);
// this sometimes gives different information
console.error("Error with feed load (error added): " + e);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",

2
src/views/NewEditProjectView.vue

@ -309,7 +309,7 @@ export default class NewEditProjectView extends Vue {
return; return;
} }
try { try {
const headers = getHeaders(this.activeDid) as AxiosRequestHeaders; const headers = (await getHeaders(this.activeDid)) as AxiosRequestHeaders;
const response = await this.axios.delete( const response = await this.axios.delete(
DEFAULT_IMAGE_API_SERVER + DEFAULT_IMAGE_API_SERVER +
"/image/" + "/image/" +

1
src/views/ProjectViewView.vue

@ -162,6 +162,7 @@
<div v-if="activeDid && isRegistered" class="mt-4"> <div v-if="activeDid && isRegistered" class="mt-4">
<div class="text-center"> <div class="text-center">
<button <button
data-testId="offerButton"
@click="openOfferDialog()" @click="openOfferDialog()"
class="block w-full text-lg font-bold 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-2 py-3 rounded-md" class="block w-full text-lg font-bold 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-2 py-3 rounded-md"
> >

8
src/views/ProjectsView.vue

@ -396,7 +396,7 @@ export default class ProjectsView extends Vue {
* @param token Authorization token * @param token Authorization token
**/ **/
async offerDataLoader(url: string) { async offerDataLoader(url: string) {
const headers = getHeaders(this.activeDid); const headers = await getHeaders(this.activeDid);
try { try {
this.isLoading = true; this.isLoading = true;
@ -443,7 +443,7 @@ export default class ProjectsView extends Vue {
async loadMoreOfferData(payload: boolean) { async loadMoreOfferData(payload: boolean) {
if (this.offers.length > 0 && payload) { if (this.offers.length > 0 && payload) {
const latestOffer = this.offers[this.offers.length - 1]; const latestOffer = this.offers[this.offers.length - 1];
await this.loadOffers(this.activeDid, `&beforeId=${latestOffer.jwtId}`); await this.loadOffers(`&beforeId=${latestOffer.jwtId}`);
} }
} }
@ -452,8 +452,8 @@ export default class ProjectsView extends Vue {
* @param issuerDid of the user * @param issuerDid of the user
* @param urlExtra additional url parameters in a string * @param urlExtra additional url parameters in a string
**/ **/
async loadOffers(issuerDid?: string, urlExtra: string = "") { async loadOffers(urlExtra: string = "") {
const url = `${this.apiServer}/api/v2/report/offers?offeredByDid=${issuerDid}${urlExtra}`; const url = `${this.apiServer}/api/v2/report/offers?offeredByDid=${this.activeDid}${urlExtra}`;
await this.offerDataLoader(url); await this.offerDataLoader(url);
} }

8
src/views/SharedPhotoView.vue

@ -54,9 +54,11 @@
service code underneath. To fix this, first make sure you have latest service code underneath. To fix this, first make sure you have latest
version by comparing your version at the bottom of "Help" with the version by comparing your version at the bottom of "Help" with the
version at the bottom of https://timesafari.app/help in a browser. After version at the bottom of https://timesafari.app/help in a browser. After
that, it may eventually work, but you can speed up the process by clearing that, it may eventually work, but you can speed up the process by
your data cache (in the browser on mobile, even if you installed it) and/or clearing your data cache (in the browser on mobile, even if you
reinstalling the app (after backing up all your data, of course).</p> installed it) and/or reinstalling the app (after backing up all your
data, of course).
</p>
</div> </div>
</section> </section>
</template> </template>

2
test-playwright/20-create-project.spec.ts

@ -43,12 +43,10 @@ test('Create new project, then search for it', async ({ page }) => {
// Search for newly-created project in /projects // Search for newly-created project in /projects
await page.goto('./projects'); await page.goto('./projects');
await page.getByRole('link', { name: 'Projects', exact: true }).click(); await page.getByRole('link', { name: 'Projects', exact: true }).click();
await page.waitForTimeout(3000); // Wait for a bit
await expect(page.locator('ul#listProjects li.border-b:nth-child(1)')).toContainText(finalRandomString); // Assumes newest project always appears first in the Projects tab list await expect(page.locator('ul#listProjects li.border-b:nth-child(1)')).toContainText(finalRandomString); // Assumes newest project always appears first in the Projects tab list
// Search for newly-created project in /discover // Search for newly-created project in /discover
await page.goto('./discover'); await page.goto('./discover');
await page.waitForTimeout(3000); // Wait for a bit
await page.getByPlaceholder('Search…').fill(finalRandomString); await page.getByPlaceholder('Search…').fill(finalRandomString);
await page.locator('#QuickSearch button').click(); await page.locator('#QuickSearch button').click();
await expect(page.locator('ul#listDiscoverResults li.border-b:nth-child(1)')).toContainText(finalRandomString); await expect(page.locator('ul#listDiscoverResults li.border-b:nth-child(1)')).toContainText(finalRandomString);

2
test-playwright/30-record-gift.spec.ts

@ -27,7 +27,7 @@ test('Record something given', async ({ page }) => {
await page.goto('./'); await page.goto('./');
await page.getByRole('heading', { name: 'Unnamed/Unknown' }).click(); await page.getByRole('heading', { name: 'Unnamed/Unknown' }).click();
await page.getByPlaceholder('What was given').fill(finalTitle); await page.getByPlaceholder('What was given').fill(finalTitle);
await page.getByRole('spinbutton', { id: 'inputGivenAmount' }).fill(randomNonZeroNumber.toString()); await page.getByRole('spinbutton').fill(randomNonZeroNumber.toString());
await page.getByRole('button', { name: 'Sign & Send' }).click(); await page.getByRole('button', { name: 'Sign & Send' }).click();
await expect(page.getByText('That gift was recorded.')).toBeVisible(); await expect(page.getByText('That gift was recorded.')).toBeVisible();

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

@ -51,7 +51,7 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
// Record something given by new contact // Record something given by new contact
await page.getByRole('heading', { name: contactName }).click(); await page.getByRole('heading', { name: contactName }).click();
await page.getByPlaceholder('What was given').fill(finalTitle); await page.getByPlaceholder('What was given').fill(finalTitle);
await page.getByRole('spinbutton').fill(randomNonZeroNumber.toString()); await page.getByRole('spinbutton', { id: 'inputGivenAmount' }).fill(randomNonZeroNumber.toString());
await page.getByRole('button', { name: 'Sign & Send' }).click(); await page.getByRole('button', { name: 'Sign & Send' }).click();
await expect(page.getByText('That gift was recorded.')).toBeVisible(); await expect(page.getByText('That gift was recorded.')).toBeVisible();

33
test-playwright/50-record-offer.spec.ts

@ -0,0 +1,33 @@
import { test, expect } from '@playwright/test';
import { importUser } from './testUtils';
test('Record an offer', async ({ page }) => {
// Generate a random string of 6 characters, skipping the "0." at the beginning
const randomString = Math.random().toString(36).substring(2, 8);
// Standard title prefix
const finalTitle = `Offer ${randomString}`;
const randomNonZeroNumber = Math.floor(Math.random() * 999) + 1;
// Create new ID for default user
await importUser(page);
// Select a project
await page.goto('./discover');
await page.locator('ul#listDiscoverResults li:nth-child(1)').click();
// Record an offer
await page.getByTestId('offerButton').click();
await page.getByTestId('inputDescription').fill(finalTitle);
await page.getByTestId('inputOfferAmount').fill(randomNonZeroNumber.toString());
await page.getByRole('button', { name: 'Sign & Send' }).click();
await expect(page.getByText('That offer was recorded.')).toBeVisible();
// Refresh home view and check gift
await page.goto('./projects');
await page.locator('li').filter({ hasText: `All ${randomNonZeroNumber} remaining` }).locator('a').first().click();
await expect(page.getByRole('heading', { name: 'Verifiable Claim Details' })).toBeVisible();
await expect(page.getByText(finalTitle, { exact: true })).toBeVisible();
const page1Promise = page.waitForEvent('popup');
await page.getByRole('link', { name: 'View on the Public Server' }).click();
const page1 = await page1Promise;
});

2
test-playwright/testUtils.js

@ -21,6 +21,8 @@ export async function importUser(page, id) {
await page.getByText('You have a seed').click(); await page.getByText('You have a seed').click();
await page.getByPlaceholder('Seed Phrase').fill(seedPhrase); await page.getByPlaceholder('Seed Phrase').fill(seedPhrase);
await page.getByRole('button', { name: 'Import' }).click(); await page.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sectionUsageLimits')).toContainText('You have done');
await expect(page.locator('#sectionUsageLimits')).toContainText('You have uploaded');
// Set name // Set name
await page.getByRole('link', { name: 'Set Your Name' }).click(); await page.getByRole('link', { name: 'Set Your Name' }).click();

Loading…
Cancel
Save