Browse Source

fix image server references for tests (2 tests failing: missing function & looking for registration prompt for unregistered user)

Trent Larson 6 days ago
parent
commit
c9c3cacfbd
  1. 5
      .env.development
  2. 1
      .env.production
  3. 1
      .env.staging
  4. 27
      BUILDING.md
  5. 2
      playwright.config-local.ts
  6. 64
      src/App.vue
  7. 8
      src/components/PhotoDialog.vue
  8. 4
      src/main.ts
  9. 16
      src/router/index.ts
  10. 66
      src/views/AccountViewView.vue
  11. 5
      src/views/DiscoverView.vue
  12. 8
      src/views/GiftedDetailsView.vue
  13. 8
      src/views/NewEditProjectView.vue
  14. 8
      src/views/SharedPhotoView.vue
  15. 8
      test-playwright/35-record-gift-from-image-share.spec.ts
  16. 2
      test-playwright/40-add-contact.spec.ts
  17. 6
      vite.config.mjs

5
.env.development

@ -6,6 +6,7 @@ VITE_APP_SERVER=http://localhost:3000
# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production). # This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production).
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000 VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000
VITE_DEFAULT_IMAGE_API_SERVER=http://localhost:3000 # Using shared server by default to ease setup, which works for shared test users.
VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000 VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000
VITE_PASSKEYS_ENABLED=true VITE_PASSKEYS_ENABLED=true

1
.env.production

@ -6,5 +6,6 @@ VITE_APP_SERVER=https://timesafari.app
# This is the claim ID for actions in the BVC project. # This is the claim ID for actions in the BVC project.
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch

1
.env.staging

@ -6,6 +6,7 @@ VITE_APP_SERVER=https://test.timesafari.app
# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production). # This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production).
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch
VITE_PASSKEYS_ENABLED=true VITE_PASSKEYS_ENABLED=true

27
BUILDING.md

@ -246,32 +246,7 @@ npm run lint-fix
## Environment Configuration ## Environment Configuration
### Development See `.env.*` files for configuration.
Create a `.env.development` file:
```bash
TIME_SAFARI_APP_TITLE="TimeSafari_Dev"
VITE_APP_SERVER=http://localhost:3000
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000
VITE_DEFAULT_IMAGE_API_SERVER=http://localhost:3000
VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000
VITE_PASSKEYS_ENABLED=true
```
### Test/Staging
Create a `.env.staging` file:
```bash
TIME_SAFARI_APP_TITLE="TimeSafari_Test"
VITE_APP_SERVER=https://test.timesafari.app
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch
VITE_PASSKEYS_ENABLED=true
```
### Production
The `.env.production` file will be used automatically for production builds.
## Notes ## Notes

2
playwright.config-local.ts

@ -119,7 +119,7 @@ export default defineConfig({
*/ */
webServer: { webServer: {
command: command:
"VITE_APP_SERVER=http://localhost:8081 VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000 VITE_PASSKEYS_ENABLED=true npm run dev -- --port=8081", "VITE_APP_SERVER=http://localhost:8081 VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000 VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000 VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_PASSKEYS_ENABLED=true npm run dev -- --port=8081",
url: "http://localhost:8081", url: "http://localhost:8081",
reuseExistingServer: !process.env.CI, reuseExistingServer: !process.env.CI,
}, },

64
src/App.vue

@ -333,46 +333,46 @@ export default class App extends Vue {
stopAsking = false; stopAsking = false;
created() { // created() {
console.log( // console.log(
"Component created: Reactivity set up.", // "Component created: Reactivity set up.",
window.location.pathname, // window.location.pathname,
); // );
} // }
truncateLongWords(sentence: string) { // beforeCreate() {
return sentence // console.log("Component beforeCreate: Instance initialized.");
.split(" ") // }
.map((word) => (word.length > 30 ? word.slice(0, 30) + "..." : word))
.join(" ");
}
beforeCreate() { // beforeMount() {
console.log("Component beforeCreate: Instance initialized."); // console.log("Component beforeMount: Template is about to be rendered.");
} // }
beforeMount() { // mounted() {
console.log("Component beforeMount: Template is about to be rendered."); // console.log("Component mounted: Template is now rendered.");
} // }
mounted() { // beforeUpdate() {
console.log("Component mounted: Template is now rendered."); // console.log("Component beforeUpdate: DOM is about to be updated.");
} // }
beforeUpdate() { // updated() {
console.log("Component beforeUpdate: DOM is about to be updated."); // console.log("Component updated: DOM has been updated.");
} // }
updated() { // beforeUnmount() {
console.log("Component updated: DOM has been updated."); // console.log("Component beforeUnmount: Cleaning up before removal.");
} // }
beforeUnmount() { // unmounted() {
console.log("Component beforeUnmount: Cleaning up before removal."); // console.log("Component unmounted: Component removed from the DOM.");
} // }
unmounted() { truncateLongWords(sentence: string) {
console.log("Component unmounted: Component removed from the DOM."); return sentence
.split(" ")
.map((word) => (word.length > 30 ? word.slice(0, 30) + "..." : word))
.join(" ");
} }
async turnOffNotifications( async turnOffNotifications(

8
src/components/PhotoDialog.vue

@ -369,6 +369,14 @@ export default class PhotoDialog extends Vue {
formData.append("image", this.blob, this.fileName || "snapshot.png"); formData.append("image", this.blob, this.fileName || "snapshot.png");
formData.append("claimType", this.claimType); formData.append("claimType", this.claimType);
try { try {
if (
window.location.hostname === "localhost" &&
!DEFAULT_IMAGE_API_SERVER.includes("localhost")
) {
console.log(
"Using shared image API server, so only users on that server can play with images.",
);
}
const response = await axios.post( const response = await axios.post(
DEFAULT_IMAGE_API_SERVER + "/image", DEFAULT_IMAGE_API_SERVER + "/image",
formData, formData,

4
src/main.ts

@ -197,7 +197,7 @@ function setupGlobalErrorHandler(app: VueApp) {
); );
}; };
} }
console.log("Bootstrapping Vue app..."); // console.log("Bootstrapping Vue app...");
const app = createApp(App) const app = createApp(App)
.component("fa", FontAwesomeIcon) .component("fa", FontAwesomeIcon)
.component("camera", Camera) .component("camera", Camera)
@ -209,4 +209,4 @@ const app = createApp(App)
setupGlobalErrorHandler(app); setupGlobalErrorHandler(app);
app.mount("#app"); app.mount("#app");
console.log("Vue app mounted."); // console.log("Vue app mounted.");

16
src/router/index.ts

@ -23,8 +23,6 @@ const enterOrStart = async (
const accountsDB = await accountsDBPromise; const accountsDB = await accountsDBPromise;
const num_accounts = await accountsDB.accounts.count(); const num_accounts = await accountsDB.accounts.count();
console.log("Number of accounts: ", num_accounts);
if (num_accounts > 0) { if (num_accounts > 0) {
next(); next();
} else { } else {
@ -299,8 +297,6 @@ const router = createRouter({
routes, routes,
}); });
console.log("Initial URL:", initialPath);
// Replace initial URL to start at `/` if necessary // Replace initial URL to start at `/` if necessary
router.replace(initialPath || "/"); router.replace(initialPath || "/");
@ -319,12 +315,10 @@ const errorHandler = (
router.onError(errorHandler); // Assign the error handler to the router instance router.onError(errorHandler); // Assign the error handler to the router instance
router.beforeEach((to, from, next) => { // router.beforeEach((to, from, next) => {
console.log("Navigating to view:", to.name); // console.log("Navigating to view:", to.name);
console.log("From view:", from.name); // console.log("From view:", from.name);
next(); // next();
}); // });
console.log("Initial URL:", window.location.pathname);
export default router; export default router;

66
src/views/AccountViewView.vue

@ -365,35 +365,41 @@
<div v-if="loadingLimits" class="text-center"> <div v-if="loadingLimits" class="text-center">
Checking&hellip; <fa icon="spinner" class="fa-spin"></fa> Checking&hellip; <fa icon="spinner" class="fa-spin"></fa>
</div> </div>
<div> <div class="mb-4 text-center">
{{ limitsMessage }} {{ limitsMessage }}
</div> </div>
<div v-if="!!endorserLimits?.nextWeekBeginDateTime"> <div>
<p class="text-sm"> <p class="text-sm">
You have done You have done
<b>{{ endorserLimits.doneClaimsThisWeek }} claims</b> out of <b>{{ endorserLimits?.doneClaimsThisWeek || "?" }} claims</b> out of
<b>{{ endorserLimits.maxClaimsPerWeek }}</b> for this week. Your <b>{{ endorserLimits?.maxClaimsPerWeek || "?" }}</b> for this week.
claims counter resets at Your claims counter resets at
<b class="whitespace-nowrap">{{ <b class="whitespace-nowrap">{{
readableDate(endorserLimits.nextWeekBeginDateTime) readableDate(endorserLimits?.nextWeekBeginDateTime)
}}</b> }}</b>
</p> </p>
<p class="mt-3 text-sm"> <p class="mt-3 text-sm">
You have done You have done
<b>{{ endorserLimits.doneRegistrationsThisMonth }} registrations</b> <b
out of <b>{{ endorserLimits.maxRegistrationsPerMonth }}</b> for this >{{
month. endorserLimits?.doneRegistrationsThisMonth || "?"
<i>(You cannot register anyone else on your first day.)</i> }}
registrations</b
>
out of
<b>{{ endorserLimits?.maxRegistrationsPerMonth || "?" }}</b> for this
this month.
<i>(You cannot register anyone on your first day.)</i>
Your registration counter resets at Your registration counter resets at
<b class="whitespace-nowrap"> <b class="whitespace-nowrap">
{{ readableDate(endorserLimits.nextMonthBeginDateTime) }} {{ readableDate(endorserLimits?.nextMonthBeginDateTime) }}
</b> </b>
</p> </p>
<p class="mt-3 text-sm" v-if="!!imageLimits"> <p class="mt-3 text-sm">
You have uploaded You have uploaded
<b>{{ imageLimits?.doneImagesThisWeek }} images</b> out of <b>{{ imageLimits?.doneImagesThisWeek || "?" }} images</b> out of
<b>{{ imageLimits?.maxImagesPerWeek }}</b> for this week. Your image <b>{{ imageLimits?.maxImagesPerWeek || "?" }}</b> for this week. Your
counter resets at image counter resets at
<b class="whitespace-nowrap">{{ <b class="whitespace-nowrap">{{
readableDate(imageLimits?.nextWeekBeginDateTime) readableDate(imageLimits?.nextWeekBeginDateTime)
}}</b> }}</b>
@ -1215,7 +1221,7 @@ export default class AccountViewView extends Vue {
} }
readableDate(timeStr: string) { readableDate(timeStr: string) {
return timeStr.substring(0, timeStr.indexOf("T")); return timeStr ? timeStr.substring(0, timeStr.indexOf("T")) : "?";
} }
/** /**
@ -1230,11 +1236,11 @@ export default class AccountViewView extends Vue {
this.publicHex = identity.keys[0].publicKeyHex; this.publicHex = identity.keys[0].publicKeyHex;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64"); this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
this.derivationPath = identity.keys[0].meta?.derivationPath as string; this.derivationPath = identity.keys[0].meta?.derivationPath as string;
await this.checkLimitsFor(this.activeDid); await this.checkLimits();
} else if (account?.publicKeyHex) { } else if (account?.publicKeyHex) {
this.publicHex = account.publicKeyHex as string; this.publicHex = account.publicKeyHex as string;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64"); this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
await this.checkLimitsFor(this.activeDid); await this.checkLimits();
} }
} }
@ -1598,11 +1604,13 @@ export default class AccountViewView extends Vue {
} }
/** /**
* Use "checkLimits" instead.
*
* Asynchronously checks rate limits for the given identity. * Asynchronously checks rate limits for the given identity.
* *
* Updates component state variables `limits`, `limitsMessage`, and `loadingLimits`. * Updates component state variables `limits`, `limitsMessage`, and `loadingLimits`.
*/ */
public async checkLimitsFor(did: string) { private async checkLimitsFor(did: string) {
this.loadingLimits = true; this.loadingLimits = true;
this.limitsMessage = ""; this.limitsMessage = "";
@ -1632,9 +1640,15 @@ export default class AccountViewView extends Vue {
); );
} }
} }
const imageResp = await fetchImageRateLimits(this.axios, did); try {
if (imageResp.status === 200) { const imageResp = await fetchImageRateLimits(this.axios, did);
this.imageLimits = imageResp.data; if (imageResp.status === 200) {
this.imageLimits = imageResp.data;
} else {
this.limitsMessage = "You don't have access to upload images.";
}
} catch {
this.limitsMessage = "You cannot upload images.";
} }
} }
} catch (error) { } catch (error) {
@ -1739,6 +1753,14 @@ export default class AccountViewView extends Vue {
try { try {
const headers = await getHeaders(this.activeDid); const headers = await getHeaders(this.activeDid);
this.passkeyExpirationDescription = tokenExpiryTimeDescription(); this.passkeyExpirationDescription = tokenExpiryTimeDescription();
if (
window.location.hostname === "localhost" &&
!DEFAULT_IMAGE_API_SERVER.includes("localhost")
) {
console.log(
"Using shared image API server, so only users on that server can play with images.",
);
}
const response = await this.axios.delete( const response = await this.axios.delete(
DEFAULT_IMAGE_API_SERVER + DEFAULT_IMAGE_API_SERVER +
"/image/" + "/image/" +

5
src/views/DiscoverView.vue

@ -302,7 +302,10 @@ import InfiniteScroll from "../components/InfiniteScroll.vue";
import ProjectIcon from "../components/ProjectIcon.vue"; import ProjectIcon from "../components/ProjectIcon.vue";
import OnboardingDialog from "../components/OnboardingDialog.vue"; import OnboardingDialog from "../components/OnboardingDialog.vue";
import TopMessage from "../components/TopMessage.vue"; import TopMessage from "../components/TopMessage.vue";
import { NotificationIface, DEFAULT_PARTNER_API_SERVER } from "../constants/app"; import {
NotificationIface,
DEFAULT_PARTNER_API_SERVER,
} from "../constants/app";
import { import {
db, db,
logConsoleAndDb, logConsoleAndDb,

8
src/views/GiftedDetailsView.vue

@ -547,6 +547,14 @@ export default class GiftedDetails extends Vue {
} }
try { try {
const headers = await getHeaders(this.activeDid); const headers = await getHeaders(this.activeDid);
if (
window.location.hostname === "localhost" &&
!DEFAULT_IMAGE_API_SERVER.includes("localhost")
) {
console.log(
"Using shared image API server, so only users on that server can play with images.",
);
}
const response = await this.axios.delete( const response = await this.axios.delete(
DEFAULT_IMAGE_API_SERVER + DEFAULT_IMAGE_API_SERVER +
"/image/" + "/image/" +

8
src/views/NewEditProjectView.vue

@ -357,6 +357,14 @@ export default class NewEditProjectView extends Vue {
} }
try { try {
const headers = (await getHeaders(this.activeDid)) as AxiosRequestHeaders; const headers = (await getHeaders(this.activeDid)) as AxiosRequestHeaders;
if (
window.location.hostname === "localhost" &&
!DEFAULT_IMAGE_API_SERVER.includes("localhost")
) {
console.log(
"Using shared image API server, so only users on that server can play with images.",
);
}
const response = await this.axios.delete( const response = await this.axios.delete(
DEFAULT_IMAGE_API_SERVER + DEFAULT_IMAGE_API_SERVER +
"/image/" + "/image/" +

8
src/views/SharedPhotoView.vue

@ -183,6 +183,14 @@ export default class SharedPhotoView extends Vue {
); );
formData.append("claimType", imageType); formData.append("claimType", imageType);
if (
window.location.hostname === "localhost" &&
!DEFAULT_IMAGE_API_SERVER.includes("localhost")
) {
console.log(
"Using shared image API server, so only users on that server can play with images.",
);
}
const response = await axios.post( const response = await axios.post(
DEFAULT_IMAGE_API_SERVER + "/image", DEFAULT_IMAGE_API_SERVER + "/image",
formData, formData,

8
test-playwright/35-record-gift-from-image-share.spec.ts

@ -50,6 +50,14 @@ import path from 'path';
import { test, expect } from '@playwright/test'; import { test, expect } from '@playwright/test';
import { importUser } from './testUtils'; import { importUser } from './testUtils';
/**
* Note: by default, this test uses the test image API server.
*
* If you want to use your own image API server, you can set the
* VITE_DEFAULT_IMAGE_API_SERVER environment variable to your server's URL
* in the playwright.config-local.ts file.
*
*/
test('Record item given from image-share', async ({ page }) => { test('Record item given from image-share', async ({ page }) => {
let randomString = Math.random().toString(36).substring(2, 8); let randomString = Math.random().toString(36).substring(2, 8);

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

@ -300,7 +300,7 @@ test('Copy contact to clipboard, then import ', async ({ page, context }, testIn
return; return;
} }
console.log("Running test that copies contact details to clipboard."); // console.log("Running test that copies contact details to clipboard.");
await page.getByTestId('copySelectedContactsButtonTop').click(); await page.getByTestId('copySelectedContactsButtonTop').click();
const clipboardText = await page.evaluate(async () => { const clipboardText = await page.evaluate(async () => {
return navigator.clipboard.readText(); return navigator.clipboard.readText();

6
vite.config.mjs

@ -33,12 +33,6 @@ export default defineConfig(({ mode }) => {
fs: { fs: {
strict: false strict: false
}, },
proxy: process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test' ? {
'/api': {
target: process.env.VITE_DEFAULT_ENDORSER_API_SERVER || 'http://localhost:3000',
changeOrigin: true,
},
} : undefined,
}, },
build: { build: {
outDir: isElectron ? "dist-electron" : "dist", outDir: isElectron ? "dist-electron" : "dist",

Loading…
Cancel
Save