diff --git a/.changeset/seven-poets-repeat.md b/.changeset/seven-poets-repeat.md new file mode 100644 index 00000000000..4dbfa43161e --- /dev/null +++ b/.changeset/seven-poets-repeat.md @@ -0,0 +1,5 @@ +--- +'@builder.io/qwik-city': minor +--- + +feat: allow mocking route loaders & actions in `QwikCityMockProvider` \ No newline at end of file diff --git a/packages/docs/src/routes/api/qwik-city/api.json b/packages/docs/src/routes/api/qwik-city/api.json index fe22bfc12ca..0edf5c44c11 100644 --- a/packages/docs/src/routes/api/qwik-city/api.json +++ b/packages/docs/src/routes/api/qwik-city/api.json @@ -520,6 +520,34 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/qwik-city-component.tsx", "mdFile": "qwik-city.qwik_city_scroller.md" }, + { + "name": "QwikCityMockActionProp", + "id": "qwikcitymockactionprop", + "hierarchy": [ + { + "name": "QwikCityMockActionProp", + "id": "qwikcitymockactionprop" + } + ], + "kind": "Interface", + "content": "```typescript\nexport interface QwikCityMockActionProp \n```\n\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n[action](#)\n\n\n\n\n\n\n\n[Action](#action)<T>\n\n\n\n\nThe action function to mock.\n\n\n
\n\n[handler](#)\n\n\n\n\n\n\n\nQRL<(data: T) => RouteActionResolver>\n\n\n\n\nThe QRL function that will be called when the action is submitted.\n\n\n
", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/qwik-city-component.tsx", + "mdFile": "qwik-city.qwikcitymockactionprop.md" + }, + { + "name": "QwikCityMockLoaderProp", + "id": "qwikcitymockloaderprop", + "hierarchy": [ + { + "name": "QwikCityMockLoaderProp", + "id": "qwikcitymockloaderprop" + } + ], + "kind": "Interface", + "content": "```typescript\nexport interface QwikCityMockLoaderProp \n```\n\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n[data](#)\n\n\n\n\n\n\n\nT\n\n\n\n\nThe data to return when the loader is called.\n\n\n
\n\n[loader](#)\n\n\n\n\n\n\n\n[Loader](#loader_2)<T>\n\n\n\n\nThe loader function to mock.\n\n\n
", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/qwik-city-component.tsx", + "mdFile": "qwik-city.qwikcitymockloaderprop.md" + }, { "name": "QwikCityMockProps", "id": "qwikcitymockprops", @@ -530,7 +558,7 @@ } ], "kind": "Interface", - "content": "```typescript\nexport interface QwikCityMockProps \n```\n\n\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n[goto?](#)\n\n\n\n\n\n\n\n[RouteNavigate](#routenavigate)\n\n\n\n\n_(Optional)_\n\n\n
\n\n[params?](#)\n\n\n\n\n\n\n\nRecord<string, string>\n\n\n\n\n_(Optional)_\n\n\n
\n\n[url?](#)\n\n\n\n\n\n\n\nstring\n\n\n\n\n_(Optional)_\n\n\n
", + "content": "```typescript\nexport interface QwikCityMockProps \n```\n\n\n\n\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n[actions?](#)\n\n\n\n\n\n\n\nArray<[QwikCityMockActionProp](#qwikcitymockactionprop)<any>>\n\n\n\n\n_(Optional)_ Allow mocking actions defined with `routeAction$` function.\n\n```\n[\n {\n action: useAddUser,\n handler: $(async (data) => {\n console.log('useAddUser action called with data:', data);\n }),\n },\n];\n```\n\n\n
\n\n[goto?](#)\n\n\n\n\n\n\n\n[RouteNavigate](#routenavigate)\n\n\n\n\n_(Optional)_ Allow mocking the `goto` function returned by `useNavigate` hook.\n\n\n
\n\n[loaders?](#)\n\n\n\n\n\n\n\nArray<[QwikCityMockLoaderProp](#qwikcitymockloaderprop)<any>>\n\n\n\n\n_(Optional)_ Allow mocking data for loaders defined with `routeLoader$` function.\n\n```\n[\n {\n loader: useProductData,\n data: { product: { name: 'Test Product' } },\n },\n];\n```\n\n\n
\n\n[params?](#)\n\n\n\n\n\n\n\nRecord<string, string>\n\n\n\n\n_(Optional)_ Allow mocking the route params returned by `useLocation` hook.\n\n\n
\n\n[url?](#)\n\n\n\n\n\n\n\nstring\n\n\n\n\n_(Optional)_ Allow mocking the url returned by `useLocation` hook.\n\nDefault: `http://localhost/`\n\n\n
", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/qwik-city-component.tsx", "mdFile": "qwik-city.qwikcitymockprops.md" }, diff --git a/packages/docs/src/routes/api/qwik-city/index.mdx b/packages/docs/src/routes/api/qwik-city/index.mdx index db175d19d9f..f2f98a6c8bd 100644 --- a/packages/docs/src/routes/api/qwik-city/index.mdx +++ b/packages/docs/src/routes/api/qwik-city/index.mdx @@ -1739,6 +1739,120 @@ QWIK_CITY_SCROLLER = "_qCityScroller"; [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/qwik-city-component.tsx) +## QwikCityMockActionProp + +```typescript +export interface QwikCityMockActionProp +``` + + + + +
+ +Property + + + +Modifiers + + + +Type + + + +Description + +
+ +[action](#) + + + + + +[Action](#action)<T> + + + +The action function to mock. + +
+ +[handler](#) + + + + + +QRL<(data: T) => RouteActionResolver> + + + +The QRL function that will be called when the action is submitted. + +
+ +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/qwik-city-component.tsx) + +## QwikCityMockLoaderProp + +```typescript +export interface QwikCityMockLoaderProp +``` + + + + +
+ +Property + + + +Modifiers + + + +Type + + + +Description + +
+ +[data](#) + + + + + +T + + + +The data to return when the loader is called. + +
+ +[loader](#) + + + + + +[Loader](#loader_2)<T> + + + +The loader function to mock. + +
+ +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/qwik-city-component.tsx) + ## QwikCityMockProps ```typescript @@ -1764,6 +1878,32 @@ Description +[actions?](#) + + + + + +Array<[QwikCityMockActionProp](#qwikcitymockactionprop)<any>> + + + +_(Optional)_ Allow mocking actions defined with `routeAction$` function. + +``` +[ + { + action: useAddUser, + handler: $(async (data) => { + console.log('useAddUser action called with data:', data); + }), + }, +]; +``` + + + + [goto?](#) @@ -1774,7 +1914,31 @@ Description -_(Optional)_ +_(Optional)_ Allow mocking the `goto` function returned by `useNavigate` hook. + + + + +[loaders?](#) + + + + + +Array<[QwikCityMockLoaderProp](#qwikcitymockloaderprop)<any>> + + + +_(Optional)_ Allow mocking data for loaders defined with `routeLoader$` function. + +``` +[ + { + loader: useProductData, + data: { product: { name: 'Test Product' } }, + }, +]; +``` @@ -1789,7 +1953,7 @@ Record<string, string> -_(Optional)_ +_(Optional)_ Allow mocking the route params returned by `useLocation` hook. @@ -1804,7 +1968,9 @@ string -_(Optional)_ +_(Optional)_ Allow mocking the url returned by `useLocation` hook. + +Default: `http://localhost/` diff --git a/packages/docs/src/routes/docs/(qwikcity)/api/index.mdx b/packages/docs/src/routes/docs/(qwikcity)/api/index.mdx index ebfadd516cb..f82a14e9990 100644 --- a/packages/docs/src/routes/docs/(qwikcity)/api/index.mdx +++ b/packages/docs/src/routes/docs/(qwikcity)/api/index.mdx @@ -355,7 +355,7 @@ test.each(cases)('should render card with %s %s', async ({text, link}) => { }); ``` -> a `goto` prop can be passed to customize the `navigate` behavior during tests +> A `goto` prop can be passed to customize the `navigate` behavior during tests ```tsx title="src/components/button.spec.tsx" import { $ } from '@builder.io/qwik'; @@ -383,6 +383,82 @@ test('should render the button and navigate', async () => { }); ``` +> If you are using `routeLoader$`s in a Qwik Component that you want to test, you can provide a `loaders` prop to mock the data returned by the loaders + +```ts title="src/loaders/product.loader.ts" +import { routeLoader$ } from '@builder.io/qwik-city'; + +export const useProductData = routeLoader$(async () => { + const res = await fetch('https://.../product'); + const product = (await res.json()) as Product; + return product; +}); +``` + +```tsx title="src/components/product.tsx" +import { component$ } from '@builder.io/qwik'; + +import { useProductData } from '../loaders/product.loader'; + +export const Footer = component$(() => { + const signal = useProductData(); + return
Product name: {signal.value.product.name}
; +}); +``` + +```tsx title="src/components/product.spec.tsx" +import { createDOM } from '@builder.io/qwik/testing'; +import { test, expect } from 'vitest'; + +import { Footer } from './product'; +import { useProductData } from '../loaders/product.loader'; + +test('should render footer with product name', async () => { + const { screen, render } = await createDOM(); + const loadersMock = [ + { + loader: useProductData, + data: { product: { name: 'Test Product' } }, + }, + ]; + await render( + +