# Test Independence Requirements
## Rule
Every Cypress test MUST be independently runnable. Tests must not depend on other tests, share mutable state, or rely on execution order. Each test sets up its own preconditions.
## Requirements
### 1. Programmatic Setup (Not UI-Driven)
```typescript
// Bad — depends on previous test creating a user
it('edits user profile', () => {
cy.visit('/users/1/edit'); // assumes user 1 exists
});
// Good — creates its own data
it('edits user profile', () => {
cy.request('POST', '/api/test/users', { name: 'Alice' }).then((resp) => {
cy.visit(`/users/${resp.body.id}/edit`);
});
});
```
### 2. Authentication via cy.session or API
```typescript
// Good — session is cached, independent per test
beforeEach(() => {
cy.login('admin@test.com', 'password');
});
```
### 3. No Shared Variables Between Tests
```typescript
// Bad
let createdId: string;
it('creates item', () => { createdId = '...'; });
it('deletes item', () => { cy.request('DELETE', `/api/items/${createdId}`); });
// Good — each test is self-contained
it('creates and verifies item', () => {
cy.request('POST', '/api/items', { name: 'test' }).then((resp) => {
cy.visit(`/items/${resp.body.id}`);
cy.getByCy('item-name').should('contain', 'test');
});
});
```
### 4. Clean State Between Tests
```typescript
beforeEach(() => {
cy.request('POST', '/api/test/reset'); // reset database state
cy.clearCookies();
cy.clearLocalStorage();
});
```
## Verification
Run any single test in isolation:
```bash
npx cypress run --spec cypress/e2e/specific.cy.ts
```
If it fails alone but passes in the full suite, it violates independence.
## Anti-Patterns
- Tests that MUST run in a specific order
- Shared state via closures or global variables
- Using `after()` to create state for the next test
- Relying on database state from previous test runs
- Tests that fail on the first run but pass on retry (indicates state dependency)