The set of Cursor rules files for Node.js frontend applications.

Cursor saves the rules files in the repository in the .cursor/rules directory. Each file below is a separate .md file in this directory.

api-integration.mdc

---
description: API Integration Standards
globs: src/**/*.js
---
# API Integration Standards

## Configuration
- Use apiServer from config for base URL:
```javascript
import { config } from '~/src/config/config.js'
const baseUrl = config.get('apiServer')
```

## Making API Calls
- Use native fetch for HTTP requests (do not use Axios or other HTTP clients)
- Always include error handling
- Use JSON content type by default
- Follow RESTful conventions
- Use absolute imports with '~' alias

### Standard Pattern

```javascript
import { config } from '~/src/config/config.js'
import { statusCodes } from '~/src/server/common/constants/status-codes.js'
async function makeApiCall(request) {
try {
const response = await fetch(${config.get('apiServer')}/api/v1/endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
if (!response.ok) {
throw new Error(API call failed with status: ${response.status})
}
return await response.json()
} catch (error) {
request.logger.error(error)
throw error
}
}
```


## Error Handling
- Check response.ok status
- Log errors with request.logger
- Use statusCodes constants for response codes
- Return user-friendly error messages
- Propagate errors up for handling

## Response Processing 
- Parse JSON responses
- Validate response data structure
- Handle empty responses appropriately
- Use TypeScript-style JSDoc for type annotations

## Security
- Use HTTPS in production
- Include authorization headers when required
- Redact sensitive data in logs
- Follow security best practices

javascript.mdc

---
description: Javascript in Defra
globs: *.js
---
# JavaScript in Defra

## Language
- JavaScript
- TypeScript (for type checking only)

## Tech Stack
- Node.js + Hapi.js (do NOT use Express)
- govuk-frontend npm library
- Nunjucks templates npm library
- Webpack + Babel
- Jest + ESLint + Prettier
- SCSS + PostCSS + Stylelint

## Code Standards
- Use vanilla JavaScript (no TypeScript files)
- Use JSDoc for type annotations
- Use TypeScript for type checking only
- Use ES Modules with named exports
- Use absolute imports with '~' alias for internal project files
- Use convict for configuration management
- Use BEM-style naming with 'app-' prefix

## Project Structure
- /src/config/ - Configuration and setup
  - /nunjucks/ - Template engine setup
    - /filters/ - Custom Nunjucks filters
    - /globals/ - Global template variables
- /src/server/ - Server-side code
  - /common/ - Shared components and utilities
    - /templates/ - Base templates and layouts
    - /components/ - Reusable view components
  - /{feature}/ - Feature modules
    - controller.js - Route handlers and business logic
    - controller.test.js - Unit tests
    - index.js - Route definitions
    - /views/ - Feature-specific templates
  - router.js - Main route aggregation
  - index.js - Server setup and plugins

## Controller Patterns
- Export named functions
- Use JSDoc to document parameters
- Standard parameters: (request, h)
- Consistent error handling:
  - Try/catch blocks
  - Error logging with request.logger
  - User-friendly error responses
- Use h.view for template rendering
- Use h.redirect for navigation

## API Integration
- Use fetch for API calls
- Base URL from config
- JSON content type
- Response status checking
- Error propagation
- Consistent error handling

## Configuration
- Use config module for settings
- Environment-based configuration
- Consistent config access pattern
- Type-safe config values

## Markdown Parsing
- Use marked library for parsing markdown
- Configure marked options to match GDS styling
- Always sanitize markdown output
- Common use cases:
  - Standards content
  - Documentation
  - Help text

## Testing
- Write comprehensive Jest tests
- Test functionality, not implementation
  - End-to-end coverage
  - API: test input/output
  - UI: test behavior + use data-testid
- Use describe blocks and beforeEach for setup
- Mock external dependencies

## Template Handling
- Configure Nunjucks search paths in nunjucks.js:
  - govuk-frontend templates
  - project views directory
  - common templates
  - common components
- Use h.view with template paths relative to search paths
- Bind controller methods when used as route handlers
- Follow template inheritance patterns from gov-uk-standards
- Keep templates close to their feature modules

gov-uk-standards.mdc

---
description: GOV.UK Frontend
globs: *.njk, *.js
---
# GOV UK Frontend

## Tech Stack
- Node.js + Hapi.js
- govuk-frontend npm library
- Nunjucks templates

## Template Structure
- Use layouts/page.njk as base template
- Follow GDS template hierarchy
- Required template blocks:
  - pageTitle: Page title with " - Defra SDLC Governance Checklist" suffix
  - content: Main content area
- Use govuk-width-container for page layout
- Use govuk-main-wrapper for main content
- Use govuk-grid-row and govuk-grid-column-* for grid layouts

## Template Inheritance
- Always use search path style imports (e.g. {% extends "layouts/page.njk" %})
- Never use relative paths in extends/include statements
- Base template is at src/server/common/templates/layouts/page.njk
- Feature templates should be in src/server/{feature}/views/
- Common components in src/server/common/components/

## Component Usage
- Use GDS components with data-module="govuk-button" where needed
- Follow GDS class naming:
  - Headings: govuk-heading-xl, govuk-heading-l, etc.
  - Body text: govuk-body
  - Tables: govuk-table with appropriate child classes
  - Buttons: govuk-button, govuk-button--warning for variants
  - Forms: govuk-form-group, govuk-input, etc.
  - Error handling: govuk-error-message, govuk-error-summary

## Content Guidelines
- Follow GDS content patterns
- Use appropriate heading hierarchy
- Ensure accessible content structure
- Include proper ARIA roles and attributes
- Use semantic HTML elements

## Error Handling
- Use consistent error templates
- Display user-friendly error messages
- Include status codes where appropriate
- Provide clear next steps for users

## Navigation
- Use buildNavigation helper for consistent nav
- Implement breadcrumbs where appropriate
- Clear call-to-action buttons
- Logical page flow

## Nunjucks Filters
- Custom filters located in src/config/nunjucks/filters/
- Each filter should have its own file
- Common filters:
  - formatDate
  - formatCurrency
  - markdown (for content formatting)

playwright-testing.mdc

---
description: Playwright Testing
globs: tests/*.js
---
# Playwright Testing Rules

## Testing Philosophy
- Focus on user-visible behavior and outcomes rather than internal implementation details.
- Keep tests isolated, independent, and reflective of end-to-end user journeys.
- Test server-rendered content and interactive behaviors from a user's perspective.
- Ensure tests remain robust by avoiding strict mode locator violations through specific and scoped selectors.

## Testing Strategy

### Element Scoping and Selectors
- Always scope element checks to their containing parent to avoid matching multiple elements.
- Use relative selectors and `:has()` filters to narrow down to specific instances (e.g., table rows, details components).
- Refine selectors with regex for whitespace and exact text when needed.
- Avoid global page-level selectors for nested elements.

#### Selector Priority
1. Role-based selectors with exact text, e.g., `getByRole('button', { name: 'Submit', exact: true })`
2. ARIA label selectors, e.g., `getByLabel('Search')`
3. Component-specific class selectors with context filtering, e.g., `locator('.govuk-details__summary-text', { hasText: /Summary Text/ })`
4. Scoped locators using `:has()` and `filter()` for parent-child relationships.
5. Generic text matching as the last resort, e.g., `getByText('Content')`

### State and Interaction Testing
- Verify both initial and changed states of interactive components.
- Test interactive behaviors like clicking to expand/collapse a details component and verify resulting state changes (e.g., checking for the `open` attribute).
- Test keyboard interactions, attribute changes, and error states.
- Ensure tests cover both default views and dynamic transitions.

## Test Structure
- Place tests in the `/tests` directory with a `.spec.js` extension.
- Group related tests using `test.describe()`.
- Use `test.beforeEach()` for common setup steps.
- Write clear, descriptive test names (e.g., "should display error message when API fails").
- Always use ES Module syntax with named imports (e.g. `import { test, expect } from '@playwright/test';`).

## GDS Component Testing

### Common GDS Component Selectors
- **Details Component:**
  ```javascript
  // Target summary text within a details component
  page.locator('span.govuk-details__summary-text', { hasText: /Summary Text/ });
  // Target content within the details component
  page.locator('div.govuk-details__text').filter({ hasText: /Content Text/ });
  ```
- **Table Component:**
  ```javascript
  // Target table by accessible caption or role
  page.getByRole('table', { name: 'Caption Text' });
  // Target a specific row using role and text
  page.getByRole('row', { name: 'Row Content' });
  // Use scoped selectors within a row
  const row = page.getByRole('row', { name: 'Row Content' });
  row.locator('.govuk-tag');
  ```
- **Tags:**
  ```javascript
  // Target a tag with specific text
  page.locator('.govuk-tag', { hasText: 'Tag Text' });
  // Verify tag color variants with regex matching
  await expect(tag).toHaveClass(/govuk-tag--blue/);
  await expect(tag).toHaveClass(/govuk-tag--green/);
  await expect(tag).toHaveClass(/govuk-tag--red/);
  ```
- **Buttons:**
  ```javascript
  page.getByRole('button', { name: 'Button Text' });
  ```

### GDS Component Testing Patterns
- **Details Component:**
  - Test summary text visibility.
  - Test expand/collapse functionality by clicking the summary and asserting the open attribute.
  - Verify that the expanded content renders the expected text.
  - Include keyboard accessibility tests.
- **Tables:**
  - Verify the presence of captions, headers, and cell content.
  - Check responsive behavior using scoped selectors for rows.
- **Form Components:**
  - Test validation messages and error summaries.
  - Verify correct display of hint texts and input states.

### Accessibility Testing
- Integrate axe-core (e.g., using `@axe-core/playwright`) to run automated accessibility scans.
- Test keyboard navigation flows and focus management.
- Verify that screen reader announcements are correct.
- Check for meeting color contrast standards and proper ARIA attributes.
- Example:
  ```javascript
  import AxeBuilder from '@axe-core/playwright';
  const results = await new AxeBuilder({ page }).analyze();
  expect(results.violations).toEqual([]);
  ```

### Server-Side Testing Considerations
- Test complete user journeys including form submissions, redirects, and session handling.
- Verify that server-rendered content is correct.
- Include tests for error pages and status codes.
- Ensure that navigation flows are smooth and predictable across the application.

navigation.mdc

---
description: Navigation Standards
globs: src/config/nunjucks/context/*.js, src/views/layouts/*.njk
---
# Navigation Standards

## Navigation Configuration

Navigation items should be managed through the `buildNavigation` helper function:

```javascript
// src/config/nunjucks/context/build-navigation.js
export function buildNavigation(request) {
  return [
    {
      text: 'Menu Item',
      url: '/path',
      isActive: request?.path?.startsWith('/path')
    }
  ]
}
```

## Key Components

1. **Navigation Items Structure**
   - text: Display text for the menu item
   - url: URL path for the menu item
   - isActive: Function to determine active state
   
2. **Active State**
   - Use `startsWith()` for paths with sub-pages
   - Handle null/undefined paths with optional chaining
   - Match exact paths for single-page items

## Implementation Steps

1. Update `buildNavigation.js`:
   - Add new navigation items
   - Define active state logic
   - Maintain order based on information architecture

2. Add corresponding routes in `base.js` or feature-specific route files:
   ```javascript
   {
     method: 'GET',
     path: '/new-path',
     handler: (request, h) => {
       return h.view('view-name', {
         currentPath: request.path
       });
     }
   }
   ```

3. Create view templates for new navigation items:
   ```nunjucks
   {% extends "layouts/layout.njk" %}
   {% block content %}
     {# Page content here #}
   {% endblock %}
   ```

## Testing

1. Update `build-navigation.test.js` when adding new items:
   ```javascript
   test('should mark new item as active when on its path', () => {
     const request = { path: '/new-path' }
     const nav = buildNavigation(request)
     expect(nav[index].isActive).toBe(true)
   })
   ```

2. Add Playwright tests for navigation behavior:
   ```javascript
   test('should navigate to new page when clicking menu item', async ({ page }) => {
     await page.click('text=Menu Item')
     await expect(page).toHaveURL('/new-path')
   })
   ```

## Best Practices

1. **Consistency**
   - Follow GDS navigation patterns
   - Use consistent naming conventions
   - Maintain logical grouping of items

2. **Accessibility**
   - Ensure keyboard navigation works
   - Maintain clear active states
   - Follow ARIA best practices

3. **Maintenance**
   - Keep navigation items in sync with routes
   - Document any special navigation logic
   - Test all navigation paths

## Common Patterns

1. **Sub-Navigation**
   ```javascript
   {
     text: 'Parent',
     url: '/parent',
     isActive: request?.path?.startsWith('/parent'),
     items: [
       {
         text: 'Child',
         url: '/parent/child',
         isActive: request?.path === '/parent/child'
       }
     ]
   }
   ```

2. **Conditional Navigation**
   ```javascript
   {
     text: 'Admin',
     url: '/admin',
     isActive: request?.path?.startsWith('/admin'),
     show: request?.auth?.isAdmin
   }
   ```

## Error Handling

- Handle undefined/null request objects
- Validate navigation item properties
- Log navigation errors appropriately