diff --git a/packages/app-core/test-kit/index.ts b/packages/app-core/test-kit/index.ts index 516c07f6..31146633 100644 --- a/packages/app-core/test-kit/index.ts +++ b/packages/app-core/test-kit/index.ts @@ -22,6 +22,7 @@ export class AppDefDriver { private fs: IMemFileSystem; private moduleSystem: ICommonJsModuleSystem; private dirListeners: Array = []; + private manifestListeners: Set<(manifest: IAppManifest) => void> = new Set(); private fileListeners: Record void>> = {}; private exportsListeners: Record void>> = {}; private lastManifest: IAppManifest | null = null; @@ -62,6 +63,7 @@ export class AppDefDriver { fsApi: this.fsApi, onManifestUpdate: (manifest) => { this.lastManifest = manifest; + this.dispatchManifestUpdate(); }, }); this.lastManifest = manifest; @@ -121,9 +123,20 @@ export class AppDefDriver { movedFilePath, }); } + addManifestListener(cb: (manifest: IAppManifest) => void) { + this.manifestListeners.add(cb); + } + removeManifestListener(cb: (manifest: IAppManifest) => void) { + this.manifestListeners.delete(cb); + } + private dispatchManifestUpdate() { + for (const listener of this.manifestListeners) { + listener(this.lastManifest!); + } + } async render({uri = '/'}: {uri?: string} = {}) { const { app } = this.options; - const { fsApi, importModule, lastManifest } = this; + const { fsApi, importModule } = this; if (!app.callServerMethod) { throw new Error('app.callServerMethod is not defined'); @@ -142,7 +155,7 @@ export class AppDefDriver { ); }, importModule: this.importModule, - manifest: lastManifest!, + manifest: this.lastManifest!, onCaughtError() {/**/}, setUri(_uri: string) { // ToDo: implement @@ -150,15 +163,23 @@ export class AppDefDriver { uri, }); const unmount = await app.render(container, createProps(uri)); + let lastUri = uri; + const rerender = ({uri = '/'}: {uri?: string} = {})=>{ + lastUri = uri; + return app.render(container, createProps(uri)); + } + const manifestListener = () => { + void rerender({uri: lastUri}); + }; + this.addManifestListener(manifestListener); return { - dispose() { + dispose: ()=> { unmount(); container.remove(); + this.removeManifestListener(manifestListener) }, container, - rerender({uri = '/'}: {uri?: string} = {}) { - return app.render(container, createProps(uri)); - } + rerender }; } dispose() { diff --git a/packages/define-remix-app/src/manifest-to-router.tsx b/packages/define-remix-app/src/manifest-to-router.tsx index 1a66d045..bda31d2a 100644 --- a/packages/define-remix-app/src/manifest-to-router.tsx +++ b/packages/define-remix-app/src/manifest-to-router.tsx @@ -130,7 +130,7 @@ export const fileToRoute = ( prevUri: { current: string }, callServerMethod: (filePath: string, methodName: string, args: unknown[]) => Promise, ): RouteObject => { - const key = filePath; + const key = filePath + "#" + exportNames.join(','); let module = loadedModules.get(key); if (!module) { module = nonMemoFileToRoute( diff --git a/packages/define-remix-app/test/define-remix.spec.ts b/packages/define-remix-app/test/define-remix.spec.ts index ed6519dd..ae308d33 100644 --- a/packages/define-remix-app/test/define-remix.spec.ts +++ b/packages/define-remix-app/test/define-remix.spec.ts @@ -1200,7 +1200,7 @@ describe('define-remix', () => { it('should render links returned by the links function', async () => { const { driver } = await getInitialManifest({ [rootPath]: rootWithLayout2, - [indexPath]: pageWithLinks, + [indexPath]: pageWithLinks('Home'), }); const { dispose, container } = await driver.render({ uri: '' }); @@ -1215,6 +1215,35 @@ describe('define-remix', () => { dispose(); }); + it('should support having the links function added and removed', async () => { + const { driver } = await getInitialManifest({ + [rootPath]: rootWithLayout2, + [indexPath]: namedPage('Home'), + }); + + const { dispose, container } = await driver.render({ uri: '' }); + + await expect(() => container.textContent) + .retry() + .to.include('Layout|App|Home'); + + + const link = container.querySelector('link') + expect(link).to.equal(null); + + driver.addOrUpdateFile(indexPath, pageWithLinks('HomeUpdated')); + + + await expect(() => container.textContent) + .retry() + .to.include('Layout|App|HomeUpdated'); + + const updatedLink = container.querySelector('link') + expect(updatedLink?.getAttribute('href')) + .to.include('some.css'); + + dispose(); + }); }) }); }); diff --git a/packages/define-remix-app/test/test-cases/roots.ts b/packages/define-remix-app/test/test-cases/roots.ts index 9866156a..0d285de0 100644 --- a/packages/define-remix-app/test/test-cases/roots.ts +++ b/packages/define-remix-app/test/test-cases/roots.ts @@ -77,7 +77,8 @@ export const simpleLayout = transformTsx(` ); } `); -export const pageWithLinks = transformTsx(` + +export const pageWithLinks =(name: string)=> transformTsx(` import React from 'react'; import { Outlet, @@ -90,7 +91,7 @@ export const pageWithLinks = transformTsx(` } export default function Layout() { return ( -
Home|
+
${name}|
); } `);