diff --git a/README.md b/README.md index fbc4fe9..2c9aabd 100644 --- a/README.md +++ b/README.md @@ -62,15 +62,26 @@ yarn lint yarn test ``` +### Clean + +Removes the `.next` and `node_modules` folders and runs `yarn install` to clean up the local workspace + +```bash +yarn clean +``` + ### Take Screenshots + If you are making changes that impact the UI, ensure to test the change on different view ports. Run the following to auto capture screenshots when tests run. Note that this only runs when you run this command locally. #### Take screenshots of home page + ```bash yarn capture-screenshots ``` #### Take screenshots of a specific page + ```bash PAGE_PATH=/commodities yarn capture-screenshots ``` @@ -116,4 +127,5 @@ yarn dev - Docker ### 🌐 Useful Tools -- [ColorKit](https://colorkit.co/color-palette-generator/272f33-4e5d66-9BB9CB-cddce5-e6eef2/) - Color Palette Generator \ No newline at end of file + +- [ColorKit](https://colorkit.co/color-palette-generator/272f33-4e5d66-9BB9CB-cddce5-e6eef2/) - Color Palette Generator diff --git a/app/error.tsx b/app/error.tsx new file mode 100644 index 0000000..4461bdb --- /dev/null +++ b/app/error.tsx @@ -0,0 +1,35 @@ +'use client'; + +import { Button, Center, Flex, Heading, Text } from '@chakra-ui/react'; +import layoutConfig from './_config/layout'; + +export default function Error({ + error, + reset, +}: { + error: Error; + reset: () => void; +}) { + return ( +
+ + + Something went wrong! + + {error.message} + + +
+ ); +} diff --git a/app/not-found.tsx b/app/not-found.tsx index 9d680a2..a7ef8c5 100644 --- a/app/not-found.tsx +++ b/app/not-found.tsx @@ -1,8 +1,8 @@ 'use client'; import NextLink from 'next/link'; -import { Link, Center, Flex, Heading } from '@chakra-ui/react'; -import GetColor from '@/app/_hooks/colorSelector'; +import { Button, Center, Flex, Heading } from '@chakra-ui/react'; +import layoutConfig from './_config/layout'; export default function NotFound() { return ( @@ -11,7 +11,7 @@ export default function NotFound() { flexDirection="column" alignItems="center" gap="24px" - maxWidth="1500px" + maxWidth={layoutConfig.maxWidth} > - + diff --git a/app/playground/client-error/page.client.tsx b/app/playground/client-error/page.client.tsx new file mode 100644 index 0000000..3f669a8 --- /dev/null +++ b/app/playground/client-error/page.client.tsx @@ -0,0 +1,7 @@ +'use client'; + +const PageClient = () => { + throw new Error('This is a simulated client rendering error.'); +}; + +export default PageClient; diff --git a/app/playground/client-error/page.tsx b/app/playground/client-error/page.tsx new file mode 100644 index 0000000..d24bd61 --- /dev/null +++ b/app/playground/client-error/page.tsx @@ -0,0 +1,8 @@ +import PageClient from './page.client'; + +// Avoid statically building this page during build. +export const dynamic = 'force-dynamic'; + +export default async function Page() { + return ; +} diff --git a/app/playground/page.tsx b/app/playground/page.tsx index 858bbdd..a5d7e66 100644 --- a/app/playground/page.tsx +++ b/app/playground/page.tsx @@ -6,7 +6,7 @@ import { } from './_api'; import { ICommodity, IPost } from '../_types'; -// Force dynamic fetching during runtime for playground +// Avoid statically building this page during build. export const dynamic = 'force-dynamic'; export const metadata: Metadata = { @@ -23,12 +23,14 @@ export default async function Page() { posts = await getPostsForCategoryFromMockApi(); } catch (error) { console.error('Failed to fetch posts data:', error); + throw error; } try { commodity = await getCommodityByNameFromStagingApi('Wine'); } catch (error) { console.error('Failed to fetch commodity data:', error); + throw error; } return ; diff --git a/app/playground/server-error/page.tsx b/app/playground/server-error/page.tsx new file mode 100644 index 0000000..de49ad7 --- /dev/null +++ b/app/playground/server-error/page.tsx @@ -0,0 +1,6 @@ +// Avoid statically building this page during build. +export const dynamic = 'force-dynamic'; + +export default async function Page() { + throw new Error('This is a simulated server rendering error.'); +} diff --git a/tests/playwright/playground/error-boundary.test.tsx b/tests/playwright/playground/error-boundary.test.tsx new file mode 100644 index 0000000..cd276e3 --- /dev/null +++ b/tests/playwright/playground/error-boundary.test.tsx @@ -0,0 +1,22 @@ +import { test, expect } from '@playwright/test'; + +test('server rendering errors should get caught and gracefully render error', async ({ + page, +}) => { + await page.goto('/playground/server-error'); + await expect(page.locator('h1')).toContainText('Something went wrong!'); + // Error messages for server rendering get replaced for security during builds + await expect(page.locator('samp')).toContainText( + 'An error occurred in the Server Components render.', + ); +}); + +test('client rendering errors should get caught and gracefully render error', async ({ + page, +}) => { + await page.goto('/playground/client-error'); + await expect(page.locator('h1')).toContainText('Something went wrong!'); + await expect(page.locator('samp')).toContainText( + 'This is a simulated client rendering error', + ); +});