Skip to content

Commit

Permalink
Fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lemonmade committed May 18, 2024
1 parent 3a7af33 commit bf92d79
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 25 deletions.
22 changes: 11 additions & 11 deletions packages/async/source/AsyncFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,11 @@ export class AsyncFetch<Data = unknown, Input = unknown> {
? this.initial
: new AsyncFetchCall(this.function);

const finalizeFetchCall = () => () => {
const finalizeFetchCall = () => {
if (this.runningSignal.peek() === fetchCall) {
this.runningSignal.value = undefined;
}

if (fetchCall.signal.aborted) return;

this.finishedSignal.value = fetchCall;
};

Expand All @@ -100,7 +98,7 @@ export class AsyncFetch<Data = unknown, Input = unknown> {
export class AsyncFetchCall<Data = unknown, Input = unknown> {
readonly promise: AsyncFetchPromise<Data, Input>;
readonly function: AsyncFetchFunction<Data, Input>;
readonly input!: Input;
readonly input?: Input;

get signal() {
return this.abortController.signal;
Expand Down Expand Up @@ -162,16 +160,18 @@ export class AsyncFetchCall<Data = unknown, Input = unknown> {

call = (input?: Input, {signal}: {signal?: AbortSignal} = {}) => {
if (this.runningSignal.peek() || this.signal.aborted) {
throw new Error(`Can’t perform fetch()`);
return Promise.reject(new Error(`Can’t perform fetch()`));
}

if (signal) {
signal.addEventListener('abort', () => {
this.abortController.abort();
});
}
Object.assign(this, {input});

signal?.addEventListener('abort', () => {
this.abortController.abort();
});

this.function(input!, {signal}).then(this.resolve, this.reject);
Promise.resolve()
.then(() => this.function(input!, {signal: this.abortController.signal}))
.then(this.resolve, this.reject);

return this.promise;
};
Expand Down
18 changes: 9 additions & 9 deletions packages/async/source/AsyncModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,30 @@ export class AsyncModule<Module> {
readonly id?: string;

get module() {
return this.loadAction.value;
return this.fetchModule.value;
}

get value() {
return this.loadAction.value;
return this.fetchModule.value;
}

get error() {
return this.loadAction.error;
return this.fetchModule.error;
}

get promise() {
return this.loadAction.promise;
return this.fetchModule.promise;
}

get status() {
return this.loadAction.status;
return this.fetchModule.status;
}

get isLoading() {
return this.loadAction.isRunning;
return this.fetchModule.isRunning;
}

private readonly loadAction: AsyncFetch<Module>;
private readonly fetchModule: AsyncFetch<Module>;

constructor(load: AsyncModuleLoader<Module>) {
const id = (load as any).id;
Expand All @@ -50,7 +50,7 @@ export class AsyncModule<Module> {
Symbol.for('quilt')
]?.asyncModules?.get(id);

this.loadAction = new AsyncFetch(
this.fetchModule = new AsyncFetch(
() => (typeof load === 'function' ? load() : load.import()),
{initial: preloadedModule},
);
Expand All @@ -59,7 +59,7 @@ export class AsyncModule<Module> {
load = ({force = false} = {}) =>
!force && (this.isLoading || this.status !== 'pending')
? this.promise
: this.loadAction.call();
: this.fetchModule.call();

import = this.load;
}
8 changes: 4 additions & 4 deletions packages/preact-async/source/AsyncContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export function AsyncContext({
cache,
children,
}: RenderableProps<{
cache: AsyncFetchCache;
cache?: AsyncFetchCache;
}>) {
const browser = useBrowserDetails();
const browser = useBrowserDetails({optional: true});
const internals = useRef<{
hydrated: Signal<boolean>;
deserialized: boolean;
Expand All @@ -30,7 +30,7 @@ export function AsyncContext({
const {hydrated, deserialized} = internals.current;

if (typeof document === 'object') {
if (!deserialized) {
if (cache != null && browser != null && !deserialized) {
const serialization = browser.serializations.get('quilt:fetch:hydrated');
if (Array.isArray(serialization)) cache.restore(serialization);

Expand All @@ -40,7 +40,7 @@ export function AsyncContext({
useLayoutEffect(() => {
hydrated.value = true;
}, []);
} else {
} else if (cache != null && browser != null) {
browser.serializations.set('quilt:fetch:cache', () => cache.serialize());
}

Expand Down
2 changes: 1 addition & 1 deletion packages/preact-async/source/hooks/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {AsyncFetchCacheContext} from '../context.ts';

export const useAsyncFetchCache = AsyncFetchCacheContext.use;

export async function useAsyncFetch<Data, Input>(
export function useAsyncFetch<Data, Input>(
fetchFunction: AsyncFetchFunction<Data, Input>,
options?: AsyncFetchCacheGetOptions<Data, Input>,
) {
Expand Down
88 changes: 88 additions & 0 deletions tests/e2e/async.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,4 +350,92 @@ describe('async', () => {
`Hello from an async component!`,
);
});

it('can server render components using an async fetch', async () => {
await using workspace = await createWorkspace({fixture: 'empty-app'});

await workspace.fs.write({
'browser.tsx': multiline`
import '@quilted/quilt/globals';
import {Browser, BrowserContext} from '@quilted/quilt/browser';
import {hydrate} from 'preact';
import App from './App.tsx';
const element = document.querySelector('#app')!;
const browser = new Browser();
hydrate(<BrowserContext browser={browser}><App /></BrowserContext>, element);
`,
'server.tsx': multiline`
import '@quilted/quilt/globals';
import {RequestRouter} from '@quilted/quilt/request-router';
import {renderToResponse} from '@quilted/quilt/server';
import {BrowserAssets} from 'quilt:module/assets';
import App from './App.tsx';
const router = new RequestRouter();
const assets = new BrowserAssets();
router.get('/data', async () => {
return new Response('Hello world!');
});
// For all GET requests, render our React application.
router.get(async (request) => {
const response = await renderToResponse(<App />, {
request,
assets,
});
return response;
});
export default router;
`,
'App.tsx': multiline`
import {useMemo} from 'preact/hooks';
import {Suspense} from 'preact/compat';
import {useBrowserRequest} from '@quilted/quilt/browser';
import {
AsyncContext,
AsyncFetchCache,
useAsyncFetch,
} from '@quilted/quilt/async';
export default function App() {
const cache = useMemo(() => new AsyncFetchCache(), []);
return (
<AsyncContext cache={cache}>
<Suspense fallback={"Loading..."}>
<Async />
</Suspense>
</AsyncContext>
);
}
function Async() {
const {url} = useBrowserRequest();
const fetched = useAsyncFetch(async () => {
const response = await fetch(new URL('/data', url));
const text = await response.text();
return text;
}, {key: 'data'});
return <div>{fetched.value}</div>
}
`,
});

const server = await startServer(workspace);
const noJSPage = await server.openPage('/', {
javaScriptEnabled: false,
});

const noJSPageContent = await noJSPage.textContent('body');
expect(noJSPageContent).toBe(`Hello world!`);
});
});

0 comments on commit bf92d79

Please sign in to comment.