Skip to content

Commit

Permalink
fix: make promises work with new Error (#579)
Browse files Browse the repository at this point in the history
* wip

* Add test for error classin promises
  • Loading branch information
emilkowalski authored Feb 16, 2025
1 parent 99d3d93 commit ccd132a
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,17 @@ class Observer {
const toastSettings: PromiseIExtendedResult =
typeof promiseData === 'object' ? (promiseData as PromiseIExtendedResult) : { message: promiseData };

this.create({ id, type: 'error', description, ...toastSettings });
} else if (response instanceof Error) {
shouldDismiss = false;

const promiseData = typeof data.error === 'function' ? await data.error(response) : data.error;
const description =
typeof data.description === 'function' ? await data.description(response) : data.description;

const toastSettings: PromiseIExtendedResult =
typeof promiseData === 'object' ? (promiseData as PromiseIExtendedResult) : { message: promiseData };

this.create({ id, type: 'error', description, ...toastSettings });
} else if (data.success !== undefined) {
shouldDismiss = false;
Expand Down
91 changes: 91 additions & 0 deletions test/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,97 @@ export default function Home({ searchParams }: any) {
>
Render close button
</button>
<button
data-testid="extended-promise"
className="button"
onClick={() =>
toast.promise(
new Promise((resolve) => {
setTimeout(() => {
resolve({ name: 'Sonner' });
}, 2000);
}),
{
loading: 'Loading...',
success: (data: any) => ({
message: `${data.name} toast has been added`,
description: 'Custom description for the Success state',
}),
error: {
message: 'An error occurred',
description: undefined,
action: {
label: 'Retry',
onClick: () => {
console.log('retrying');
},
},
},
description: 'Global description',
},
)
}
>
Extended Promise Toast
</button>

<button
data-testid="extended-promise-error"
className="button"
onClick={() =>
toast.promise(
new Promise((_, reject) => {
setTimeout(() => {
reject(new Error('Simulated error'));
}, 2000);
}),
{
loading: 'Loading...',
success: (data: any) => ({
message: `${data.name} toast has been added`,
description: 'Custom description for the Success state',
}),
error: {
message: 'An error occurred',
description: undefined,
action: {
label: 'Retry',
onClick: (event) => {
event.preventDefault();
console.log('retrying');
},
},
},
description: 'Global description',
},
)
}
>
Extended Promise Error Toast
</button>
<button
data-testid="error-promise"
className="button"
onClick={() => {
const whatWillHappen = async () => {
throw new Error('Not implemented');
};

toast.promise(whatWillHappen, {
loading: 'Saving project...',
success: (result: any) => {
if (result?.ok) {
return 'Project saved';
} else {
return `${result?.error}`;
}
},
error: (e) => `Error Raise: ${e}`,
});
}}
>
Error Promise Toast
</button>
{showAutoClose ? <div data-testid="auto-close-el" /> : null}
{showDismiss ? <div data-testid="dismiss-el" /> : null}
<Toaster
Expand Down
42 changes: 42 additions & 0 deletions test/tests/basic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,48 @@ test.describe('Basic functionality', () => {
await expect(toast.promise(rejectedPromise, {}).unwrap()).rejects.toThrow('Promise rejected');
});

test('promise toast with extended configuration', async ({ page }) => {
await page.getByTestId('extended-promise').click();

// Check loading state
await expect(page.getByText('Loading...')).toHaveCount(1);

// Check success state with custom message and description
await expect(page.getByText('Sonner toast has been added')).toHaveCount(1);
await expect(page.getByText('Custom description for the Success state')).toHaveCount(1);

// Verify global description is not shown (overridden by success description)
await expect(page.getByText('Global description')).toHaveCount(0);
});

test('promise toast with extended error configuration', async ({ page }) => {
await page.getByTestId('extended-promise-error').click();

// Check loading state
await expect(page.getByText('Loading...')).toHaveCount(1);

// Check error state
await expect(page.getByText('An error occurred')).toHaveCount(1);

// Verify action button is present
const actionButton = page.getByText('Retry');
await expect(actionButton).toHaveCount(1);

// Click retry button and verify it doesn't close the toast (due to preventDefault)
await actionButton.click();
await expect(page.getByText('An error occurred')).toHaveCount(1);
});

test('promise toast with Error object rejection', async ({ page }) => {
await page.getByTestId('error-promise').click();

// Check loading state
await expect(page.getByText('Saving project...')).toHaveCount(1);

// Check error state shows the error message correctly
await expect(page.getByText('Error Raise: Error: Not implemented')).toHaveCount(1);
});

test('render custom jsx in toast', async ({ page }) => {
await page.getByTestId('custom').click();
await expect(page.getByText('jsx')).toHaveCount(1);
Expand Down

0 comments on commit ccd132a

Please sign in to comment.