Skip to main content

End to End Testing

This project uses Cypress for comprehensive end-to-end testing to ensure the application works correctly from a user's perspective.

Additional Resources

  • Online docs
  • Cypress local quick reference: cypress/README.md

Prerequisites

Before running Cypress tests, ensure you have the following setup:

Talawa API Setup

  1. Important: The Talawa API must be properly installed, configured, and running before executing any Cypress tests. The tests depend on API endpoints being available and functional.
  2. Please follow the complete installation guide at: https://github.com/PalisadoesFoundation/talawa-api/blob/develop/INSTALLATION.md

Application Server

Ensure your local development server is running on http://localhost:4321.

Directory Structure

The tests follow the Page Object Model pattern for maintainability.

cypress/
├── e2e/
│ ├── Auth/
│ ├── AdminPortal/
│ │ ├── Dashboard/
│ │ ├── Organizations/
│ │ ├── People/
│ │ ├── Events/
│ │ ├── ActionItems/
│ │ ├── Posts/
│ │ ├── Advertisements/
│ │ ├── Venues/
│ │ └── Tags/
│ ├── UserPortal/
│ │ ├── Dashboard/
│ │ ├── OrganizationDiscovery/
│ │ ├── EventDiscovery/
│ │ ├── VolunteerSignup/
│ │ ├── Posts/
│ │ ├── Profile/
│ │ └── Transactions/
│ ├── SharedComponents/
│ ├── E2EFlows/
│ ├── ErrorScenarios/
│ ├── CascadingEffects/
│ ├── MultiOrganization/
│ └── Accessibility/
├── fixtures/
├── pageObjects/
│ ├── base/
│ ├── AdminPortal/
│ ├── UserPortal/
│ └── shared/
└── support/

Key Components:

  1. e2e/: Contains all test specification files organized by feature
  2. fixtures/: Static data used in tests (JSON files, images, etc.)
  3. pageObjects/: Page Object Model implementation for maintainable test code
  4. support/: Custom commands and utilities to extend Cypress functionality

Running Tests

Follow these steps to run end to end tests

Available Commands


# Open Cypress Test Runner (Interactive Mode)
# Preferred for Debugging

pnpm run cy:open

# Run all tests in headless mode

pnpm run cy:run

Cypress Configuration Defaults

The E2E configuration in cypress.config.ts is:

  • specPattern: cypress/e2e/**/*.cy.ts
  • testIsolation: true
  • retries: runMode: 2, openMode: 0
  • defaultCommandTimeout: 30000
  • requestTimeout, responseTimeout, pageLoadTimeout: 30000

Running Specific Tests

There are multiple testing modes.

Interactive Mode

For running specific tests with visual feedback, use the Interactive Mode where you can view all test specs and run individual tests:

pnpm run cy:open

Headless Mode

For running specific tests in headless mode, use the subset scripts below. These commands start the app server automatically before executing Cypress:

# Run Admin Portal specs
pnpm run cy:run:admin

# Run User Portal specs
pnpm run cy:run:user

# Run Auth specs
pnpm run cy:run:auth

# Run Shared Components specs
pnpm run cy:run:shared

For a single spec file, use pnpm run cy:open and select the spec in the interactive runner.

Writing Tests

Follow these best practices when writing tests.

Page Object Model

This project follows the Page Object Model pattern for better test maintenance:

// Example usage of a portal-aligned page object
import { MemberManagementPage } from '../../../pageObjects/AdminPortal/MemberManagementPage';

const memberManagementPage = new MemberManagementPage();

it('searches a member', () => {
memberManagementPage
.openFromDrawer()
.searchMemberByName('Wilt Shepherd')
.verifyMemberInList('Wilt Shepherd');
});

Use the base class in cypress/pageObjects/base/BasePage.ts when creating new portal page objects so helpers remain typed and chainable.

Shared Page Object Utilities

Use shared helpers in cypress/pageObjects/shared/ to avoid repeating common modal and table interactions across page objects.

import { ModalActions } from '../shared/ModalActions';
import { TableActions } from '../shared/TableActions';

const table = new TableActions('.MuiDataGrid-root');
const modal = new ModalActions('[role="dialog"]');

table
.waitVisible()
.clickRowActionByText(
'Praise Norris',
'[data-testid="removeMemberModalBtn"]',
);

modal.waitVisible().clickByTestId('removeMemberBtn');

Guidelines:

  • Prefer data-testid selectors first, then role/semantic selectors.
  • Keep helper methods typed and chainable.
  • Keep network mocking in specs or support utilities; page object helpers should only perform UI interactions.

Organization Setup Workflow Pattern

Use cypress/e2e/AdminPortal/Organizations/OrganizationSetup.cy.ts as the reference pattern for organization setup scenarios in the Admin Portal.

Supporting page objects:

  • cypress/pageObjects/AdminPortal/OrganizationSetupPage.ts
  • cypress/pageObjects/AdminPortal/OrganizationSettingsPage.ts
  • cypress/pageObjects/AdminPortal/MemberManagementPage.ts

The workflow covers:

  • Happy path: create organization -> configure settings -> validate branding input -> invite member
  • Negative path: duplicate organization conflict
  • Permission path: non-admin user blocked from admin org setup route
  • Org switching: move between two organizations from /admin/orglist

Recommended assertions:

  • Wait on GraphQL operations with cy.waitForGraphQLOperation(...)
  • Verify both UI state (toast/text/URL) and API payload/response when practical
  • Keep cleanup deterministic with cy.cleanupTestOrganization(...)

Example shape:

describe('Organization setup workflow', () => {
afterEach(() => {
cy.clearAllGraphQLMocks();
cy.clearCookies();
cy.clearLocalStorage();
});

it('create -> configure -> invite', () => {
cy.loginByApi('admin');
cy.mockGraphQLOperation('OrganizationFilterList', (req) => req.continue());
cy.mockGraphQLOperation('createOrganization', (req) => req.continue());
cy.mockGraphQLOperation('CreateOrganizationMembership', (req) =>
req.continue(),
);

// Create organization through UI
// Update organization settings in /admin/orgsetting/:orgId
// Validate branding input via organisationImage control
// Add member from People tab
});
});

Custom Commands

Common commands defined in cypress/support/commands.ts:

  • cy.loginByApi(role): Logs in programmatically via GraphQL mutation (bypassing UI).

    • Roles: 'admin', 'superAdmin', 'user'.
    • Usage: cy.loginByApi('admin').
  • cy.assertToast(message): Waits for a toast notification and asserts its text.

    • Usage: cy.assertToast('Organization created successfully').
  • cy.clearAllGraphQLMocks(): Resets all GraphQL request interceptors.

See API-driven test data management for data setup commands like createTestOrganization.

GraphQL Utilities

To reduce duplication and improve reliability, use the GraphQL helpers defined in cypress/support/graphql-utils.ts. These helpers intercept GraphQL requests by operationName and provide a consistent API to mock, alias, and await calls.

The interceptor respects CYPRESS_API_URL via Cypress.env('apiUrl'), and falls back to **/graphql if not set.

// Mock a successful operation using a fixture
cy.mockGraphQLOperation(
'OrganizationListBasic',
'api/graphql/organizations.success.json',
);

// Wait for the mocked operation
cy.waitForGraphQLOperation('OrganizationListBasic');

// Mock a GraphQL error response
cy.mockGraphQLError(
'CreateOrganization',
'Organization name already exists',
'CONFLICT',
);

// Alias a live operation and wait for it
cy.aliasGraphQLOperation('OrganizationListBasic');
cy.waitForGraphQLOperation('OrganizationListBasic');

Mock cleanup and test isolation

Because testIsolation is set to true, Cypress resets browser state between tests. Keep GraphQL mock cleanup in afterEach so custom intercepts stay scoped and predictable across specs and shards:

afterEach(() => {
cy.clearAllGraphQLMocks();
});

If multiple tests in the same spec target the same operationName, explicitly clean up at the end of each test:

it('mocks a successful query', () => {
cy.mockGraphQLOperation(
'OrganizationListBasic',
'api/graphql/organizations.success.json',
);
// test steps...
cy.clearAllGraphQLMocks();
});

Best practices:

  • Keep testIsolation: true as the default for E2E reliability.
  • In parallel/sharded runs, keep mocks scoped per test and reset intercepts after each test.
  • If multiple mocks target the same operation, explicitly clean up between them or scope each mock to a single test.

Test Data

Use fixtures for consistent test data:

// Load test data from fixtures
cy.fixture('users').then((users) => {
// Use users data in tests
});

Fixture library structure

Fixtures are organized by domain under cypress/fixtures/ to keep tests deterministic and consistent:

  • auth/ - credential and user fixtures for login flows
  • admin/ - organizations, events, people, action items, advertisements, tags, venues
  • user/ - posts, volunteers, campaigns, donations
  • api/graphql/ - GraphQL responses grouped by operationName

Datasets are intentionally minimal, include edge cases (empty arrays, long names, Unicode), and avoid PII.

Note: auth/users.json contains user metadata (id, name, email, role). Use auth/credentials.json for login credentials in Cypress tests.

Example usage with GraphQL utilities:

cy.mockGraphQLOperation(
'OrganizationListBasic',
'api/graphql/organizations.success.json',
);

cy.mockGraphQLOperation(
'CreateOrganization',
'api/graphql/createOrganization.success.json',
);

cy.mockGraphQLOperation(
'CreateOrganization',
'api/graphql/createOrganization.error.conflict.json',
);

API-driven test data management

When a spec needs real data against talawa-api (instead of mocks), use the custom Cypress commands backed by Node tasks in cypress/support/commands.ts. These helpers keep setup/cleanup consistent and avoid leaking state between specs:

  • cy.setupTestEnvironment(options?) → creates an organization and returns { orgId }.
  • cy.createTestOrganization(payload) → creates an organization and returns { orgId }.
  • cy.seedTestData('events' | 'volunteers' | 'posts', payload) → creates events, volunteers, or posts and returns IDs for reuse.
  • cy.cleanupTestOrganization(orgId, options?) → deletes the org and (optionally) any test users you created.

The Node tasks handle GraphQL requests directly, so they can be used even when tests are running headless in CI. Credentials are resolved from env vars first, then from fixtures:

  • CYPRESS_E2E_ADMIN_EMAIL / CYPRESS_E2E_ADMIN_PASSWORD
  • CYPRESS_E2E_SUPERADMIN_EMAIL / CYPRESS_E2E_SUPERADMIN_PASSWORD
  • CYPRESS_E2E_USER_EMAIL / CYPRESS_E2E_USER_PASSWORD

Example usage:

let orgId = '';
const userIds: string[] = [];

before(() => {
cy.setupTestEnvironment().then(({ orgId: createdOrgId }) => {
orgId = createdOrgId;
});
});

after(() => {
if (orgId) {
cy.cleanupTestOrganization(orgId, { userIds });
}
});

it('seeds event data', () => {
cy.seedTestData('events', { orgId }).then(({ eventId }) => {
expect(eventId).to.be.a('string').and.not.equal('');
});
});

it('seeds post data', () => {
cy.seedTestData('posts', { orgId }).then(({ postId }) => {
expect(postId).to.be.a('string').and.not.equal('');
});
});

it('seeds volunteer data', () => {
cy.seedTestData('events', { orgId }).then(({ eventId }) => {
cy.seedTestData('volunteers', { eventId }).then(({ userId }) => {
if (userId) {
userIds.push(userId);
}
});
});
});

Best practices:

  • Keep data creation inside before/beforeEach, and cleanup in after/afterEach.
  • Use unique names to avoid collisions (E2E Org ${Date.now()}, etc.).
  • If you seed volunteers without supplying userId, a user is created for you. Pass those IDs to cleanupTestOrganization via options.userIds to avoid leaking accounts.

Example usage with JSON fixtures:

cy.fixture('admin/organizations').then((data) => {
expect(data.organizations).to.have.length(2);
});

Test Coverage Report

After running your Cypress tests, you can generate detailed HTML coverage reports to analyze code coverage:

  1. Run Cypress tests to collect coverage data:

    pnpm run cy:run
  2. Generate HTML coverage report using nyc:

    npx nyc --reporter=html
  3. View the coverage report in your browser:

    open coverage/index.html

The HTML report provides an interactive view of:

  1. Overall coverage percentages (statements, branches, functions, lines)
  2. File-by-file coverage breakdown
  3. Detailed line-by-line coverage highlighting
  4. Uncovered code sections for easy identification

Note: Coverage data is collected during test execution and stored in the .nyc_output directory. The HTML report is generated in the coverage/ directory.

Contributing

When adding new tests:

  1. Follow the existing directory structure
  2. Use Page Object Model pattern
  3. Add appropriate fixtures for test data
  4. Ensure tests are independent and repeatable
  5. Document any new custom commands

For more information about Cypress testing, visit the official Cypress documentation.