Test Exercises
This document contains exercises for testing the Task Manager application using all four frameworks. Complete each section to build a comprehensive test suite.
Exercise 1: Cypress Tests
1.1 Authentication Tests
Create cypress/e2e/auth/login.cy.js:
describe('Login', () => {
beforeEach(() => {
cy.visit('/login');
});
// Exercise: Implement these tests
it('displays the login form');
it('logs in with valid credentials');
it('shows error with invalid credentials');
it('validates required fields');
it('redirects to dashboard after login');
it('persists session after page reload');
});
Create cypress/e2e/auth/registration.cy.js:
describe('Registration', () => {
beforeEach(() => {
cy.visit('/register');
});
// Exercise: Implement these tests
it('displays the registration form');
it('registers a new user successfully');
it('shows error when email already exists');
it('validates password requirements');
it('validates email format');
});
1.2 Task Management Tests
Create cypress/e2e/tasks/crud.cy.js:
describe('Task CRUD Operations', () => {
beforeEach(() => {
cy.login('test@example.com', 'password123');
cy.visit('/dashboard');
});
// Exercise: Implement these tests
describe('Create Task', () => {
it('creates a new task with all fields');
it('creates a task with minimum required fields');
it('validates required title field');
});
describe('Read Tasks', () => {
it('displays all user tasks');
it('shows task details');
it('displays empty state when no tasks');
});
describe('Update Task', () => {
it('updates task title');
it('changes task status');
it('changes task priority');
it('updates due date');
});
describe('Delete Task', () => {
it('deletes a task');
it('confirms before deleting');
it('shows success message after deletion');
});
});
1.3 Custom Commands
Create cypress/support/commands.js:
// Exercise: Implement these custom commands
Cypress.Commands.add('login', (email, password) => {
// TODO: Implement login command
});
Cypress.Commands.add('createTask', (taskData) => {
// TODO: Implement create task command
});
Cypress.Commands.add('deleteTask', (taskId) => {
// TODO: Implement delete task command
});
Cypress.Commands.add('filterTasks', (filters) => {
// TODO: Implement filter tasks command
});
Exercise 2: Playwright Tests
2.1 Page Objects
Create tests/pages/LoginPage.ts:
import { Page, Locator, expect } from '@playwright/test';
export class LoginPage {
readonly page: Page;
// Exercise: Define locators
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly loginButton: Locator;
readonly errorMessage: Locator;
constructor(page: Page) {
this.page = page;
// TODO: Initialize locators
}
// Exercise: Implement methods
async goto() {}
async login(email: string, password: string) {}
async expectError(message: string) {}
async expectLoggedIn() {}
}
Create tests/pages/DashboardPage.ts:
import { Page, Locator, expect } from '@playwright/test';
export class DashboardPage {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
// Exercise: Implement these methods
async goto() {}
async createTask(task: TaskData) {}
async getTaskCount(): Promise<number> {}
async filterByStatus(status: string) {}
async filterByPriority(priority: string) {}
async searchTasks(query: string) {}
}
interface TaskData {
title: string;
description?: string;
status?: string;
priority?: string;
dueDate?: string;
}
2.2 Test Suites
Create tests/e2e/tasks.spec.ts:
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
import { DashboardPage } from '../pages/DashboardPage';
test.describe('Task Management', () => {
let loginPage: LoginPage;
let dashboardPage: DashboardPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
dashboardPage = new DashboardPage(page);
await loginPage.goto();
await loginPage.login('test@example.com', 'password123');
});
// Exercise: Implement these tests
test('creates a new task', async () => {
// TODO
});
test('updates task status via drag and drop', async () => {
// TODO
});
test('filters tasks by status', async () => {
// TODO
});
test('searches for tasks', async () => {
// TODO
});
test('deletes a task', async () => {
// TODO
});
});
2.3 API Tests
Create tests/api/tasks.api.spec.ts:
import { test, expect } from '@playwright/test';
test.describe('Tasks API', () => {
let authToken: string;
test.beforeAll(async ({ request }) => {
// TODO: Get auth token
});
// Exercise: Implement these API tests
test('GET /api/tasks returns user tasks', async ({ request }) => {
// TODO
});
test('POST /api/tasks creates a new task', async ({ request }) => {
// TODO
});
test('PUT /api/tasks/:id updates a task', async ({ request }) => {
// TODO
});
test('DELETE /api/tasks/:id deletes a task', async ({ request }) => {
// TODO
});
test('GET /api/tasks with filters', async ({ request }) => {
// TODO
});
});
Exercise 3: Cucumber Tests
3.1 Feature Files
Create features/authentication.feature:
Feature: User Authentication
As a user
I want to authenticate with the application
So that I can manage my tasks
# Exercise: Complete these scenarios
Background:
Given the following users exist:
| email | password | name |
| test@example.com | password123 | Test User |
Scenario: Successful login
# TODO: Write steps
Scenario: Failed login with wrong password
# TODO: Write steps
Scenario: User registration
# TODO: Write steps
Scenario: Logout
# TODO: Write steps
Create features/tasks.feature:
Feature: Task Management
As an authenticated user
I want to manage my tasks
So that I can track my work
Background:
Given I am logged in as "test@example.com"
# Exercise: Complete these scenarios
Scenario: Create a new task
# TODO: Write steps
Scenario: View all tasks
# TODO: Write steps
Scenario: Update task status
# TODO: Write steps
Scenario: Delete a task
# TODO: Write steps
Scenario Outline: Filter tasks by status
Given I have tasks with different statuses
When I filter by status "<status>"
Then I should only see tasks with status "<status>"
Examples:
| status |
| todo |
| in_progress |
| done |
Scenario: Search for tasks
# TODO: Write steps
3.2 Step Definitions
Create features/step_definitions/auth.steps.ts:
import { Given, When, Then, DataTable } from '@cucumber/cucumber';
import { expect } from '@playwright/test';
import { CustomWorld } from '../../support/world';
// Exercise: Implement these step definitions
Given('the following users exist:', async function (this: CustomWorld, dataTable: DataTable) {
// TODO
});
Given('I am logged in as {string}', async function (this: CustomWorld, email: string) {
// TODO
});
When('I login with email {string} and password {string}', async function (
this: CustomWorld,
email: string,
password: string
) {
// TODO
});
Then('I should be on the dashboard', async function (this: CustomWorld) {
// TODO
});
Then('I should see an error message {string}', async function (
this: CustomWorld,
message: string
) {
// TODO
});
Create features/step_definitions/tasks.steps.ts:
import { Given, When, Then, DataTable } from '@cucumber/cucumber';
import { expect } from '@playwright/test';
import { CustomWorld } from '../../support/world';
// Exercise: Implement these step definitions
When('I create a task with:', async function (this: CustomWorld, dataTable: DataTable) {
// TODO
});
When('I update the task {string} status to {string}', async function (
this: CustomWorld,
taskTitle: string,
status: string
) {
// TODO
});
When('I delete the task {string}', async function (this: CustomWorld, taskTitle: string) {
// TODO
});
When('I filter by status {string}', async function (this: CustomWorld, status: string) {
// TODO
});
When('I search for {string}', async function (this: CustomWorld, query: string) {
// TODO
});
Then('I should see {int} tasks', async function (this: CustomWorld, count: number) {
// TODO
});
Then('I should see the task {string}', async function (this: CustomWorld, taskTitle: string) {
// TODO
});
Then('I should not see the task {string}', async function (this: CustomWorld, taskTitle: string) {
// TODO
});
Exercise 4: Capybara Tests (Rails)
4.1 Feature Specs
Create spec/features/authentication_spec.rb:
require 'rails_helper'
RSpec.describe 'Authentication', type: :feature do
let!(:user) { create(:user, email: 'test@example.com', password: 'password123') }
# Exercise: Implement these tests
describe 'Login' do
it 'logs in with valid credentials' do
# TODO
end
it 'shows error with invalid credentials' do
# TODO
end
it 'redirects to requested page after login' do
# TODO
end
end
describe 'Registration' do
it 'registers a new user' do
# TODO
end
it 'validates required fields' do
# TODO
end
it 'validates email uniqueness' do
# TODO
end
end
describe 'Logout' do
it 'logs out the user' do
# TODO
end
end
end
Create spec/features/tasks_spec.rb:
require 'rails_helper'
RSpec.describe 'Task Management', type: :feature do
let(:user) { create(:user) }
let!(:tasks) { create_list(:task, 5, user: user) }
before do
login_as(user)
end
# Exercise: Implement these tests
describe 'Viewing tasks' do
it 'displays all user tasks' do
# TODO
end
it 'shows task details' do
# TODO
end
end
describe 'Creating tasks' do
it 'creates a new task' do
# TODO
end
it 'validates required fields' do
# TODO
end
end
describe 'Updating tasks' do
it 'updates task title' do
# TODO
end
it 'changes task status' do
# TODO
end
end
describe 'Deleting tasks' do
it 'deletes a task' do
# TODO
end
end
describe 'Filtering tasks' do
it 'filters by status' do
# TODO
end
it 'filters by priority' do
# TODO
end
end
describe 'Searching tasks' do
it 'finds tasks by title' do
# TODO
end
end
end
4.2 Page Objects
Create spec/support/pages/login_page.rb:
class LoginPage
include Capybara::DSL
# Exercise: Implement this page object
def visit_page
# TODO
end
def fill_email(email)
# TODO
end
def fill_password(password)
# TODO
end
def submit
# TODO
end
def login(email, password)
# TODO
end
def has_error?(message)
# TODO
end
end
Create spec/support/pages/dashboard_page.rb:
class DashboardPage
include Capybara::DSL
# Exercise: Implement this page object
def visit_page
# TODO
end
def create_task(title:, description: nil, priority: 'medium', status: 'todo')
# TODO
end
def task_count
# TODO
end
def has_task?(title)
# TODO
end
def delete_task(title)
# TODO
end
def filter_by_status(status)
# TODO
end
def search(query)
# TODO
end
end
Exercise 5: CI/CD Configuration
5.1 GitHub Actions for Cypress
Create .github/workflows/cypress.yml:
# Exercise: Complete this workflow
name: Cypress Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
cypress:
runs-on: ubuntu-latest
steps:
# TODO: Add steps for:
# 1. Checkout code
# 2. Setup Node.js
# 3. Install dependencies
# 4. Start application
# 5. Run Cypress tests
# 6. Upload artifacts on failure
5.2 GitHub Actions for Playwright
Create .github/workflows/playwright.yml:
# Exercise: Complete this workflow
name: Playwright Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
playwright:
runs-on: ubuntu-latest
steps:
# TODO: Add steps for:
# 1. Checkout code
# 2. Setup Node.js
# 3. Install dependencies
# 4. Install Playwright browsers
# 5. Run Playwright tests
# 6. Upload test report
Submission Checklist
Before submitting your project, ensure you have:
Cypress
- [ ] Login/logout tests
- [ ] Registration tests
- [ ] Task CRUD tests
- [ ] Filter and search tests
- [ ] Custom commands
- [ ] Fixtures for test data
- [ ] Page objects (optional)
Playwright
- [ ] Page objects for all pages
- [ ] E2E test suite
- [ ] API test suite
- [ ] Visual regression tests (optional)
- [ ] Cross-browser configuration
Cucumber
- [ ] Feature files for all features
- [ ] Step definitions
- [ ] World object with Playwright
- [ ] Hooks for setup/teardown
- [ ] Tags for test organization
Capybara (if using Rails)
- [ ] Feature specs for all features
- [ ] Page objects
- [ ] Factories
- [ ] Shared examples
- [ ] Database cleaner configuration
CI/CD
- [ ] GitHub Actions workflow for each framework
- [ ] Test reports
- [ ] Artifact upload on failure
Documentation
- [ ] README with setup instructions
- [ ] Test coverage report
- [ ] Known issues/limitations
Bonus Challenges
- Visual Testing: Add visual regression tests with Playwright or Percy
- Performance Testing: Add Lighthouse CI for performance metrics
- Accessibility Testing: Add axe-core for a11y testing
- Load Testing: Add k6 scripts for API load testing
- Mobile Testing: Add mobile viewport tests
Good luck with your exercises!