Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silly-things-stand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/elements': patch
---

Fix elements otp test interactions
5 changes: 5 additions & 0 deletions .changeset/stale-ducks-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/shared': patch
---

Fix is known error issues due to cross-bundle scenarios where instanceof fails due to different class instances.
4 changes: 4 additions & 0 deletions integration/tests/elements/otp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('OTP @elem
await otp.pressSequentially('12');

await otp.press('ArrowLeft');
await expect(page.getByTestId('segmented-otp-1')).toHaveAttribute('data-status', 'selected');
await otp.pressSequentially('1');
await expect(otp).toHaveValue('11');
});
Expand Down Expand Up @@ -200,10 +201,13 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('OTP @elem

await otp.press('ArrowLeft');
await otp.press('ArrowLeft');
// Wait for selection to update - cursor should be on index 2 (selecting "3")
await expect(page.getByTestId('segmented-otp-2')).toHaveAttribute('data-status', 'selected');
await otp.press('Delete');

await expect(otp).toHaveValue('124');
await otp.press('ArrowRight');
await expect(page.getByTestId('segmented-otp-2')).toHaveAttribute('data-status', 'selected');
await otp.press('Delete');
await expect(otp).toHaveValue('12');
});
Expand Down
8 changes: 8 additions & 0 deletions packages/shared/src/errors/createErrorTypeGuard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ export function createErrorTypeGuard<T extends new (...args: any[]) => Value>(
if (!target) {
throw new TypeError(`${ErrorClass.kind || ErrorClass.name} type guard requires an error object`);
}
// Use duck-typing with 'kind' property to handle cross-bundle scenarios
// where instanceof fails due to different class instances
if (ErrorClass.kind && typeof target === 'object' && target !== null && 'constructor' in target) {
const targetConstructor = (target as { constructor?: { kind?: string } }).constructor;
if (targetConstructor?.kind === ErrorClass.kind) {
return true;
}
}
Comment on lines +32 to +39
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem encountered is:

  • clerk-js throws ClerkAPIResponseError instances
  • @clerk/elements uses isClerkAPIResponseError() to check errors
  • Both import from @clerk/shared, but due to bundling, they get different copies of the ClerkAPIResponseError class
  • instanceof fails across different class instances

return target instanceof ErrorClass;
}

Expand Down