diff --git a/src/member-api.js b/src/member-api.js index 98706b6f..e6cea8cc 100644 --- a/src/member-api.js +++ b/src/member-api.js @@ -90,6 +90,7 @@ export class MemberApi extends TypedEmitter { * @param {import('./roles.js').RoleIdForNewInvite} opts.roleId * @param {string} [opts.roleName] * @param {string} [opts.roleDescription] + * @param {Buffer} [opts.__testOnlyInviteId] Hard-code the invite ID. Only for tests. * @returns {Promise<( * typeof InviteResponse_Decision.ACCEPT | * typeof InviteResponse_Decision.REJECT | @@ -98,7 +99,12 @@ export class MemberApi extends TypedEmitter { */ async invite( deviceId, - { roleId, roleName = ROLES[roleId]?.name, roleDescription } + { + roleId, + roleName = ROLES[roleId]?.name, + roleDescription, + __testOnlyInviteId, + } ) { assert(isRoleIdForNewInvite(roleId), 'Invalid role ID for new invite') assert( @@ -121,7 +127,7 @@ export class MemberApi extends TypedEmitter { abortSignal.throwIfAborted() - const inviteId = crypto.randomBytes(32) + const inviteId = __testOnlyInviteId || crypto.randomBytes(32) const projectId = projectKeyToId(this.#projectKey) const projectInviteId = projectKeyToProjectInviteId(this.#projectKey) const project = await this.#dataTypes.project.getByDocId(projectId) diff --git a/test-e2e/utils.js b/test-e2e/utils.js index 99c48e03..e5695537 100644 --- a/test-e2e/utils.js +++ b/test-e2e/utils.js @@ -7,13 +7,13 @@ import { fork } from 'node:child_process' import { createRequire } from 'node:module' import { fileURLToPath } from 'node:url' import * as v8 from 'node:v8' +import { pEvent } from 'p-event' import { MapeoManager, roles } from '../src/index.js' import { kManagerReplicate, kRPC } from '../src/mapeo-manager.js' -import { once } from 'node:events' import { generate } from '@mapeo/mock-data' import { valueOf } from '../src/utils.js' -import { randomInt } from 'node:crypto' +import { randomBytes, randomInt } from 'node:crypto' import { temporaryFile, temporaryDirectory } from 'tempy' import fsPromises from 'node:fs/promises' import { kSyncState } from '../src/sync/sync-api.js' @@ -100,18 +100,25 @@ export async function invite({ const promises = [] for (const invitee of invitees) { + const inviteId = randomBytes(32) promises.push( invitorProject.$member.invite(invitee.deviceId, { roleId, roleName, + __testOnlyInviteId: inviteId, }) ) promises.push( - once(invitee.invite, 'invite-received').then(async ([invite]) => { + (async () => { + const invite = await pEvent( + invitee.invite, + 'invite-received', + (invite) => Buffer.from(invite.inviteId, 'hex').equals(inviteId) + ) await (reject ? invitee.invite.reject(invite) : invitee.invite.accept(invite)) - }) + })() ) }