Run the direct sign-up e2e scenarios on disposable accounts deleted after each scenario
This commit is contained in:
@@ -66,12 +66,13 @@ Fonctionnalité: Smoke e2e de la pile ActivityPods locale
|
||||
# point de rencontre : l'URN de membre (ancrée sur l'événement) entre dans la
|
||||
# collection `apods:attendees` de l'événement, et l'URI de l'événement dans la
|
||||
# collection des participations de la session. L'inscription à l'événement est
|
||||
# dérivée : directe, ou membre d'un de ses points de rencontre. Chaque scénario quitte
|
||||
# ce qu'il a rejoint, même en cas d'échec.
|
||||
# dérivée : directe, ou membre d'un de ses points de rencontre. Chaque scénario tourne sur un compte
|
||||
# jetable, créé puis supprimé (Pod compris) même en cas d'échec : rien ne reste dans
|
||||
# le pod d'un compte persistant.
|
||||
|
||||
@inscription-evenement
|
||||
Scénario: Rejoindre puis quitter un événement met à jour sa collection apods:attendees
|
||||
Étant donné une session Pod locale pour "alice" avec le mot de passe "Test1test"
|
||||
Étant donné une session Pod jetable avec le mot de passe "Test1test"
|
||||
Et l'application Festipod est installée sur le Pod de la session
|
||||
Et un événement "Concert direct" avec sa collection apods:attendees
|
||||
Quand la session s'inscrit à l'événement
|
||||
@@ -84,7 +85,7 @@ Fonctionnalité: Smoke e2e de la pile ActivityPods locale
|
||||
|
||||
@inscription-evenement
|
||||
Scénario: L'inscription directe et l'inscription à un point de rencontre partagent la même URN de membre
|
||||
Étant donné une session Pod locale pour "alice" avec le mot de passe "Test1test"
|
||||
Étant donné une session Pod jetable avec le mot de passe "Test1test"
|
||||
Et l'application Festipod est installée sur le Pod de la session
|
||||
Et un point de rencontre "Rdv entrée" rattaché à un événement, avec sa collection apods:attendees
|
||||
Et l'événement a aussi sa collection apods:attendees
|
||||
@@ -96,7 +97,7 @@ Fonctionnalité: Smoke e2e de la pile ActivityPods locale
|
||||
|
||||
@inscription-evenement
|
||||
Scénario: Quitter le dernier point de rencontre sans inscription directe désinscrit de l'événement
|
||||
Étant donné une session Pod locale pour "alice" avec le mot de passe "Test1test"
|
||||
Étant donné une session Pod jetable avec le mot de passe "Test1test"
|
||||
Et l'application Festipod est installée sur le Pod de la session
|
||||
Et un point de rencontre "Rdv entrée" rattaché à un événement, avec sa collection apods:attendees
|
||||
Quand la session rejoint le point de rencontre
|
||||
@@ -107,7 +108,7 @@ Fonctionnalité: Smoke e2e de la pile ActivityPods locale
|
||||
|
||||
@inscription-evenement
|
||||
Scénario: Quitter le dernier point de rencontre garde l'inscription directe
|
||||
Étant donné une session Pod locale pour "alice" avec le mot de passe "Test1test"
|
||||
Étant donné une session Pod jetable avec le mot de passe "Test1test"
|
||||
Et l'application Festipod est installée sur le Pod de la session
|
||||
Et un point de rencontre "Rdv entrée" rattaché à un événement, avec sa collection apods:attendees
|
||||
Et l'événement a aussi sa collection apods:attendees
|
||||
@@ -120,7 +121,7 @@ Fonctionnalité: Smoke e2e de la pile ActivityPods locale
|
||||
|
||||
@inscription-evenement
|
||||
Scénario: Se désinscrire de l'événement retire l'inscription directe et celles des points de rencontre
|
||||
Étant donné une session Pod locale pour "alice" avec le mot de passe "Test1test"
|
||||
Étant donné une session Pod jetable avec le mot de passe "Test1test"
|
||||
Et l'application Festipod est installée sur le Pod de la session
|
||||
Et un point de rencontre "Rdv entrée" rattaché à un événement, avec sa collection apods:attendees
|
||||
Et l'événement a aussi sa collection apods:attendees
|
||||
@@ -134,11 +135,11 @@ Fonctionnalité: Smoke e2e de la pile ActivityPods locale
|
||||
|
||||
@browser @inscription-evenement
|
||||
Scénario: Parcours : s'inscrire à un événement, rejoindre un point de rencontre, se désinscrire de l'événement avec confirmation
|
||||
Étant donné une session Pod locale pour "alice" avec le mot de passe "Test1test"
|
||||
Étant donné une session Pod jetable avec le mot de passe "Test1test"
|
||||
Et l'application Festipod est installée sur le Pod de la session
|
||||
Et un point de rencontre "Rdv parcours" rattaché à un événement, avec sa collection apods:attendees
|
||||
Et l'événement a aussi sa collection apods:attendees
|
||||
Et "alice" est connectée dans l'application avec le mot de passe "Test1test"
|
||||
Et la session est connectée dans l'application avec le mot de passe "Test1test"
|
||||
Quand dans l'application, j'ouvre l'événement
|
||||
Et dans l'application, j'appuie sur "S'inscrire à l'événement"
|
||||
Alors l'application affiche "✓ Inscrit à l'événement"
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
memberUrnOf,
|
||||
participationSecretOf,
|
||||
participationsCollectionOf,
|
||||
podLogin,
|
||||
postOutboxActivity,
|
||||
readAttendees,
|
||||
readResource,
|
||||
@@ -90,12 +91,45 @@ async function registered(world: FestipodWorld): Promise<boolean> {
|
||||
return targets(world).some(uri => items.includes(uri));
|
||||
}
|
||||
|
||||
After({ tags: '@inscription-evenement', timeout: 60000 }, async function (this: FestipodWorld) {
|
||||
if (!this.apods.session) return;
|
||||
const to = appActorUri(apodsStackConfig());
|
||||
for (const uri of targets(this)) {
|
||||
await postOutboxActivity(this.apods.session, 'Leave', uri, to).catch(() => undefined);
|
||||
/**
|
||||
* The scenarios run on a throwaway account the run creates and deletes: nothing they
|
||||
* write (events, meeting points, activities, secrets) may stay in a persistent
|
||||
* account's pod (rule_tests-never-break-the-dev-environment). Deleting the account
|
||||
* is the cleanup — the platform drops its dataset — and it runs whatever failed.
|
||||
*/
|
||||
const POD_PASSWORD = 'Test1test';
|
||||
|
||||
async function podApi(path: string, init: RequestInit): Promise<Response> {
|
||||
return fetch(`${apodsStackConfig().podProviderUrl}${path}`, { ...init, signal: AbortSignal.timeout(30000) });
|
||||
}
|
||||
|
||||
async function deleteAccount(username: string, token: string | undefined): Promise<void> {
|
||||
let bearer = token;
|
||||
if (!bearer) {
|
||||
// The sign-up may have succeeded before the login failed: log in again to get a token.
|
||||
const login = await podApi('/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username, password: POD_PASSWORD }),
|
||||
}).catch(() => undefined);
|
||||
if (!login?.ok) return;
|
||||
bearer = ((await login.json().catch(() => ({}))) as { token?: string }).token;
|
||||
}
|
||||
if (!bearer) return;
|
||||
await podApi(`/.account/${username}`, { method: 'DELETE', headers: { Authorization: `Bearer ${bearer}` } }).catch(() => undefined);
|
||||
}
|
||||
|
||||
Given('une session Pod jetable avec le mot de passe {string}', async function (this: FestipodWorld, password: string) {
|
||||
const username = `fpjet${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
||||
expect(password, 'the cleanup logs in with the shared test password').to.equal(POD_PASSWORD);
|
||||
this.apods.username = username; // recorded before the sign-up so the After hook deletes it even if the login fails
|
||||
this.apods.session = await podLogin(apodsStackConfig(), username, password);
|
||||
});
|
||||
|
||||
After({ tags: '@inscription-evenement', timeout: 120000 }, async function (this: FestipodWorld) {
|
||||
const username = this.apods.username;
|
||||
if (!username) return;
|
||||
await deleteAccount(username, this.apods.session?.token);
|
||||
});
|
||||
|
||||
Given('un événement {string} avec sa collection apods:attendees', async function (this: FestipodWorld, title: string) {
|
||||
@@ -183,7 +217,8 @@ Then('une relecture ultérieure ne réinscrit pas la session', async function (t
|
||||
|
||||
const stackUrl = (value: string | undefined, fallback: string) => (value || fallback).replace(/\/+$/, '');
|
||||
|
||||
Given('{string} est connectée dans l\'application avec le mot de passe {string}', async function (this: FestipodWorld, username: string, password: string) {
|
||||
Given('la session est connectée dans l\'application avec le mot de passe {string}', async function (this: FestipodWorld, password: string) {
|
||||
const username = required(this.apods.username, 'the throwaway account name');
|
||||
const ctx: DriveContext = {
|
||||
app: required(this.apods.appUrl, 'app URL'),
|
||||
podFront: stackUrl(process.env.POD_FRONTEND_URL, 'http://localhost:5000'),
|
||||
|
||||
@@ -16,6 +16,8 @@ export interface ApodsScenarioState {
|
||||
session?: ApodsSession;
|
||||
/** The app server URL the `@browser` scenario loads (set by the hook). */
|
||||
appUrl?: string;
|
||||
/** Name of the throwaway account a scenario created (deleted by its After hook). */
|
||||
username?: string;
|
||||
anchorUri?: string;
|
||||
meetingPointUri?: string;
|
||||
collectionUri?: string;
|
||||
|
||||
Reference in New Issue
Block a user