Skip to content

Commit

Permalink
Support ErrorBoundary in SolidJS 1.5 (#297)
Browse files Browse the repository at this point in the history
* Support ErrorBoundary in SolidJS 1.5

* Size limit
  • Loading branch information
igorkamyshev committed Mar 24, 2023
1 parent e19a0c1 commit 9a02a31
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 29 deletions.
5 changes: 5 additions & 0 deletions .changeset/kind-tips-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@farfetched/solid': patch
---

Support ErrorBoundary in SolidJS 1.5
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"react-dom": "18.2.0",
"react-router-dom": "^6.4.2",
"runtypes": "^6.5.1",
"solid-js": "1.4.8",
"solid-js": "1.5",
"typed-contracts": "^3.0.0"
}
}
2 changes: 1 addition & 1 deletion packages/solid/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"size": {
"executor": "./tools/executors/size-limit:size-limit",
"options": {
"limit": "0.7 kB",
"limit": "1 kB",
"outputPath": "dist/packages/solid"
},
"dependsOn": [
Expand Down
64 changes: 62 additions & 2 deletions packages/solid/src/__tests__/create_query_resource.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
*/

import { allSettled, fork, sample, scopeBind } from 'effector';
import { describe, expect, test, afterEach } from 'vitest';
import { describe, expect, test, afterEach, vi } from 'vitest';
import { ErrorBoundary, For, Suspense } from 'solid-js/web';
import { render, cleanup, screen } from 'solid-testing-library';
import { Provider } from 'effector-solid';
import { createMutation, createQuery, update } from '@farfetched/core';
import {
createMutation,
createQuery,
httpError,
update,
} from '@farfetched/core';
import { setTimeout } from 'timers/promises';

import { createDefer } from '../defer';
Expand Down Expand Up @@ -333,4 +338,59 @@ describe('createQueryResource', () => {
const mutationText = await screen.findByText('Mutation success');
expect(mutationText).toBeInTheDocument();
});

test('passes original FarfetchedError to ErrorBoundary', async () => {
const query = createQuery({
handler: vi.fn().mockImplementation(() => {
throw httpError({
status: 500,
statusText: 'Sorry',
response: 'Cannot',
});
}),
});

const scope = fork();

function App() {
const [data, { start }] = createQueryResource(query);

return (
<>
<button onClick={start}>Start</button>
<ErrorBoundary
fallback={(error) => (
<section>
<div>Status: {error.status}</div>
<div>Status Text: {error.statusText}</div>
<div>Response: {error.response}</div>
</section>
)}
>
<p>{JSON.stringify(data(), null, 2)}</p>
</ErrorBoundary>
</>
);
}

render(() => (
<Provider value={scope}>
<App />
</Provider>
));

const startButton = await screen.findByText('Start');
startButton.click();

await allSettled(scope);

const statusText = await screen.findByText('Status: 500');
expect(statusText).toBeInTheDocument();

const statusTextText = await screen.findByText('Status Text: Sorry');
expect(statusTextText).toBeInTheDocument();

const responseText = await screen.findByText('Response: Cannot');
expect(responseText).toBeInTheDocument();
});
});
23 changes: 19 additions & 4 deletions packages/solid/src/create_query_resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { type Query } from '@farfetched/core';

import { createDefer } from './defer';

function createQueryResource<Params, Data, Error>(
query: Query<Params, Data, Error>
function createQueryResource<Params, Data, QueryError>(
query: Query<Params, Data, QueryError>
): [
Resource<Data | undefined>,
{
Expand All @@ -23,7 +23,7 @@ function createQueryResource<Params, Data, Error>(

const { data, error, pending, start } = useUnit(query);

let dataDefer = createDefer<Data, Error>();
let dataDefer = createDefer<Data, QueryError & Error>();

createComputed(() => {
// Start Resource after Query state changes
Expand All @@ -41,7 +41,22 @@ function createQueryResource<Params, Data, Error>(
// Reject Resource after Query returns error
const currentError = error();
if (currentError !== null) {
dataDefer.reject(currentError);
/*
SolidJS introduced a breaking change in 1.5 — https://github.com/solidjs/solid/pull/1176
Since we can't pass plain objects (which are used to make errors serializable) to `reject`
So, we have to convert them to `Error` instances for SolidJS
*/
if (currentError instanceof Error || typeof currentError === 'string') {
dataDefer.reject(currentError as any);
} else {
const errorForSolid = new Error((currentError as any)?.message);

if (typeof currentError === 'object') {
Object.assign(errorForSolid, currentError);
}

dataDefer.reject(errorForSolid as any);
}
}
});

Expand Down
43 changes: 22 additions & 21 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9a02a31

Please sign in to comment.