diff --git a/evals/001-server-component/input/app/page.test.tsx b/evals/001-server-component/input/app/page.test.tsx
index cddadaf2b..d4a0c59b6 100644
--- a/evals/001-server-component/input/app/page.test.tsx
+++ b/evals/001-server-component/input/app/page.test.tsx
@@ -1,49 +1,59 @@
-import { expect, test } from 'vitest';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-test('Page is an async server component', () => {
- const pageContent = readFileSync(join(process.cwd(), 'app', 'page.tsx'), 'utf-8');
-
- // Should be an async function (server component)
- expect(pageContent).toMatch(/export\s+default\s+async\s+function|async\s+function.*Page/);
-
- // Should NOT have 'use client' directive
- expect(pageContent).not.toMatch(/['"]use client['"];?/);
+import { expect, test, vi, beforeEach } from 'vitest';
+import { renderToString } from 'react-dom/server';
+import Page from './page';
+
+// Mock fetch to test server component behavior
+const mockProducts = [
+ { id: 1, name: 'First Product' },
+ { id: 2, name: 'Second Product' },
+ { id: 3, name: 'Third Product' },
+];
+
+beforeEach(() => {
+ global.fetch = vi.fn(() =>
+ Promise.resolve({
+ json: () => Promise.resolve(mockProducts),
+ })
+ ) as any;
});
-test('Page fetches from correct API endpoint', () => {
- const pageContent = readFileSync(join(process.cwd(), 'app', 'page.tsx'), 'utf-8');
-
- // Should fetch from the correct URL
- expect(pageContent).toMatch(/api\.vercel\.app\/products/);
-
- // Should use fetch
- expect(pageContent).toMatch(/fetch\s*\(/);
-
- // Should use await for the fetch
- expect(pageContent).toMatch(/await.*fetch|fetch.*await/);
+test('Page component is async (server component)', async () => {
+ // Server components must be async functions
+ expect(Page.constructor.name).toBe('AsyncFunction');
});
-test('Page renders first product in h1 tag', () => {
- const pageContent = readFileSync(join(process.cwd(), 'app', 'page.tsx'), 'utf-8');
-
- // Should access first product (array[0] or similar)
- expect(pageContent).toMatch(/\[0\]|\bfirst\b|\.at\(0\)/i);
-
- // Should render in h1 tag
- expect(pageContent).toMatch(/
]*>.*<\/h1>/);
-
- // Should access the product name property
- expect(pageContent).toMatch(/\.name\b/);
+test('Page fetches data and renders first product', async () => {
+ // Call the async server component
+ const result = await Page();
+
+ // Render the component to HTML
+ const html = renderToString(result);
+
+ // Should render the first product name in an h1
+ expect(html).toContain(' {
- const pageContent = readFileSync(join(process.cwd(), 'app', 'page.tsx'), 'utf-8');
-
- // Should parse JSON response
- expect(pageContent).toMatch(/\.json\(\)/);
-
- // Should await the JSON parsing
- expect(pageContent).toMatch(/await.*\.json\(\)|\.json\(\).*await/);
+test('Page calls fetch with correct API endpoint', async () => {
+ await Page();
+
+ // Verify fetch was called with the correct URL
+ expect(global.fetch).toHaveBeenCalledWith(
+ expect.stringContaining('api.vercel.app/products'),
+ expect.anything()
+ );
+});
+
+test('Page renders h1 element with product name', async () => {
+ const result = await Page();
+ const html = renderToString(result);
+
+ // Check that h1 contains the product name
+ const h1Match = html.match(/]*>(.*?)<\/h1>/);
+ expect(h1Match).toBeTruthy();
+ expect(h1Match?.[1]).toContain('First Product');
});
diff --git a/evals/022-prefer-server-actions/input/app/page.test.tsx b/evals/022-prefer-server-actions/input/app/page.test.tsx
index 145c07261..0c465243a 100644
--- a/evals/022-prefer-server-actions/input/app/page.test.tsx
+++ b/evals/022-prefer-server-actions/input/app/page.test.tsx
@@ -1,49 +1,55 @@
import { expect, test } from 'vitest';
import { render, screen } from '@testing-library/react';
-import { readFileSync } from 'fs';
-import { join } from 'path';
import Page from './page';
-test('renders contact form component', () => {
+test('renders contact form with heading', () => {
render();
expect(screen.getByText('Contact Us')).toBeDefined();
});
-test('uses server action instead of client-side submission', () => {
- const content = readFileSync(join(process.cwd(), 'app', 'ContactForm.tsx'), 'utf-8');
-
- expect(content).not.toMatch(/['"]use client['"];?/);
- expect(content).not.toMatch(/onSubmit|fetch\s*\(|useState|preventDefault/);
- expect(content).toMatch(/['"]use server['"];?/);
- expect(content).toMatch(/async\s+function\s+\w+.*FormData/);
-});
+test('form has all required input fields', () => {
+ render();
+
+ // Check for name input
+ const nameInput = screen.getByLabelText(/name/i) || screen.getByPlaceholderText(/name/i);
+ expect(nameInput).toBeDefined();
+ expect(nameInput.getAttribute('name')).toBe('name');
-test('processes form data using FormData API', () => {
- const content = readFileSync(join(process.cwd(), 'app', 'ContactForm.tsx'), 'utf-8');
-
- expect(content).toMatch(/formData\.get\s*\(\s*['"]name['"]\s*\)/);
- expect(content).toMatch(/formData\.get\s*\(\s*['"]email['"]\s*\)/);
- expect(content).toMatch(/formData\.get\s*\(\s*['"]message['"]\s*\)/);
+ // Check for email input
+ const emailInput = screen.getByLabelText(/email/i) || screen.getByPlaceholderText(/email/i);
+ expect(emailInput).toBeDefined();
+ expect(emailInput.getAttribute('name')).toBe('email');
+
+ // Check for message input (textarea or input)
+ const messageInput = screen.getByLabelText(/message/i) || screen.getByPlaceholderText(/message/i);
+ expect(messageInput).toBeDefined();
+ expect(messageInput.getAttribute('name')).toBe('message');
});
-test('has proper form structure with action attribute', () => {
- const content = readFileSync(join(process.cwd(), 'app', 'ContactForm.tsx'), 'utf-8');
-
- expect(content).toMatch(/