diff --git a/.changeset/dirty-friends-kick.md b/.changeset/dirty-friends-kick.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/dirty-friends-kick.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/integration/models/application.ts b/integration/models/application.ts index c8a6b2df2aa..e3593c3f594 100644 --- a/integration/models/application.ts +++ b/integration/models/application.ts @@ -92,6 +92,11 @@ export const application = ( buildOutput += `\n${msg}`; log(msg); }, + // Only ignore stdio locally to work around Next.js .Trash folder EPERM errors on macOS. + // In CI we want to see the full build output for debugging. + // See https://github.com/vercel/next.js/issues/60334 + // eslint-disable-next-line turbo/no-undeclared-env-vars + stdio: process.env.CI ? undefined : 'ignore', }); }, get buildOutput() { diff --git a/integration/testUtils/usersService.ts b/integration/testUtils/usersService.ts index a95114a6fb7..e668f86e72f 100644 --- a/integration/testUtils/usersService.ts +++ b/integration/testUtils/usersService.ts @@ -125,15 +125,36 @@ export const createUserService = (clerkClient: ClerkClient) => { }; }, createBapiUser: async fakeUser => { - return await clerkClient.users.createUser({ - emailAddress: fakeUser.email !== undefined ? [fakeUser.email] : undefined, - password: fakeUser.password, - firstName: fakeUser.firstName, - lastName: fakeUser.lastName, - phoneNumber: fakeUser.phoneNumber !== undefined ? [fakeUser.phoneNumber] : undefined, - username: fakeUser.username, - skipPasswordRequirement: fakeUser.password === undefined, - }); + try { + return await clerkClient.users.createUser({ + emailAddress: fakeUser.email !== undefined ? [fakeUser.email] : undefined, + firstName: fakeUser.firstName, + lastName: fakeUser.lastName, + password: fakeUser.password, + phoneNumber: fakeUser.phoneNumber !== undefined ? [fakeUser.phoneNumber] : undefined, + skipPasswordRequirement: fakeUser.password === undefined, + username: fakeUser.username, + }); + } catch (error: unknown) { + if (typeof error === 'object' && error !== null && 'status' in error && error.status === 429) { + const clerkError = error as { + status: number; + retryAfter?: number; + clerkTraceId?: string; + errors?: Array<{ message: string }>; + }; + const details = [ + `Retry-After: ${clerkError.retryAfter ?? 'not provided'} seconds`, + clerkError.clerkTraceId ? `Trace ID: ${clerkError.clerkTraceId}` : null, + clerkError.errors?.length > 0 ? `API Errors: ${clerkError.errors.map(e => e.message).join(', ')}` : null, + ] + .filter(Boolean) + .join(' | '); + + throw new Error(`Rate limit exceeded (HTTP 429) during createBapiUser. ${details}`, { cause: error }); + } + throw error; + } }, getOrCreateUser: async fakeUser => { const existingUser = await self.getUser({ email: fakeUser.email }); @@ -186,13 +207,13 @@ export const createUserService = (clerkClient: ClerkClient) => { createFakeOrganization: async userId => { const name = faker.animal.dog(); const organization = await clerkClient.organizations.createOrganization({ - name: faker.animal.dog(), createdBy: userId, + name, }); return { + delete: () => clerkClient.organizations.deleteOrganization(organization.id), name, organization, - delete: () => clerkClient.organizations.deleteOrganization(organization.id), } satisfies FakeOrganization; }, createFakeAPIKey: async (userId: string) => {