Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lesson 5: Topic 5 #4

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
505bb26
Cloned feature/alerts-and-frames into feature/alerts-and-frames-with-…
aasimsyed Apr 13, 2024
4dd5baf
installed the 'cypress-iframe' plugin to do Lesson 4.2 tests
aasimsyed Apr 13, 2024
1294ff5
revised the frames test to utilized the 'cypress-iframe' plugin
aasimsyed Apr 13, 2024
95cff28
added 'chromeWebSecurity: false' for Sauce Demo page workaround
aasimsyed Apr 14, 2024
4d57305
added Sauce Demo credentials and AdBlock URLs in fixtures
aasimsyed Apr 14, 2024
38d4d21
refactored 'visitWithAdBlocker' to use fixture file
aasimsyed Apr 14, 2024
d3b50d3
added Sauce Demo spec
aasimsyed Apr 14, 2024
295ff6b
added error handling to commands.js
aasimsyed Apr 14, 2024
9bb6caa
using the https URL
aasimsyed Apr 14, 2024
20dfee0
removed placeholder comments
aasimsyed Apr 14, 2024
ae159bc
suppressing logs for the blocked external scripts
aasimsyed Apr 14, 2024
d5b43e0
removed a comment
aasimsyed Apr 14, 2024
16666cd
optimized
aasimsyed Apr 14, 2024
d7d2d24
optimized the alerts/frames specs
aasimsyed Apr 14, 2024
61ded08
separated e2e and api tests into respective directories and updated c…
aasimsyed Apr 16, 2024
082c7af
removed example.json; added apiRequest() and createBooking() commands
aasimsyed Apr 16, 2024
63acdb9
updated no cache visit commmand
aasimsyed Apr 16, 2024
3f27701
added fixture for booking; created getToken function; added specs for…
aasimsyed Apr 16, 2024
9e889a8
added ajv for schema validation
aasimsyed Apr 16, 2024
00f5591
added schema validation library
aasimsyed Apr 17, 2024
c574b7b
added schema files based on API docs
aasimsyed Apr 17, 2024
75f2fc7
added fixture for udpate methods
aasimsyed Apr 17, 2024
28ba3d5
added schema compile/validate function
aasimsyed Apr 17, 2024
29a0068
updated auth token in apiRequest, added deleteBooking
aasimsyed Apr 17, 2024
abba6d8
updated getNewToken to use baseUrl
aasimsyed Apr 17, 2024
16fe7b4
package files
aasimsyed Apr 17, 2024
3dfce7b
implemented all the api test spec files
aasimsyed Apr 17, 2024
2e655cc
added README.md
aasimsyed Apr 17, 2024
1902ef5
added PR link to README
aasimsyed Apr 17, 2024
fcfc285
fixed typo
aasimsyed Apr 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
110 changes: 109 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,109 @@
# coding-temple-cypress-playground
# API Test Suite Documentation for Restful Booker

## Overview

This repository contains a comprehensive API test suite for the Restful Booker platform, designed to ensure the reliability and correctness of its API endpoints through automated testing using Cypress.

## Prerequisites

- Node.js (version 12 or higher)
- npm (comes with Node.js)
- Cypress
- AJV and AJV-formats for schema validation (for validating API responses against JSON schemas)

Ensure all dependencies are installed by running:

```bash
npm install cypress ajv ajv-formats --save-dev
```

## Installation

Clone the repository and install dependencies to set up the project on your local machine:

```bash
git clone https://github.com/aasimsyed/coding-temple-cypress-playground
cd coding-temple-cypress-playground
npm install
```

## Running Tests

To open the Cypress Test Runner for interactive testing:

```bash
npx cypress open
```

To run tests headlessly suitable for CI environments:

```bash
npx cypress run
```

## Configuration

The cypress.config.js file is configured to handle environment variables and setup preferences:

```javascript
const { defineConfig } = require("cypress");

module.exports = defineConfig({
e2e: {
env: {
restfulBookerUrl: 'https://restful-booker.herokuapp.com'
},
chromeWebSecurity: false,
supportFile: 'cypress/support/commands.js',
specPattern: [
'cypress/integration/e2e/**/*.spec.js',
'cypress/integration/api/**/*.spec.js'
],
setupNodeEvents(on, config) {
// Event listeners can be defined here
}
}
});
```

## Custom Commands

Custom Cypress commands enhance test readability and reusability:

- *apiRequest*: Abstracts making API requests with dynamic inputs.
- *createBooking*: Wraps the apiRequest to create bookings.
- *deleteBooking*: Utilizes apiRequest to delete bookings based on ID.

These are defined in *cypress/support/commands.js*.

## Schema Validation

API response validation is performed using AJV combined with schemas defined in cypress/schemas. This ensures responses adhere to expected formats, crucial for API integrity.

## Using Fixtures

Fixtures are used to manage and maintain test data separate from test logic, located under cypress/fixtures. This allows easy management of test data without altering the test scripts.

## Best Practices Employed

- *Modular Test Structure*: Each API endpoint has dedicated test files under cypress/integration, making tests easier to manage and debug.
- *Environment Abstraction*: Configuration details are abstracted into cypress.config.js, allowing easy changes without code adjustments.
- *Schema Validation*: Ensures the API's output remains consistent, catching potential breaking changes.
- *Custom Commands*: Reduces code duplication and increases the maintainability of tests.
- *Efficient Use of Fixtures*: Separates test data from test logic, improving test clarity and ease of updates.

## Potential Future Improvements

- *Parallel Testing*: Implement Cypress's parallel execution capabilities to reduce test run times.
- *Increased Coverage*: Expand tests to cover more scenarios and edge cases.
- *Continuous Integration*: Integrate with CI/CD pipelines for automated running of tests upon code commits or at scheduled intervals.
- *Security Testing*: Integrate security-focused tests to identify and mitigate potential vulnerabilities.

## Project URL

- https://github.com/aasimsyed/coding-temple-cypress-playground
- PR for these change: https://github.com/aasimsyed/coding-temple-cypress-playground/pull/4

## Conclusion

The implemented test suite serves as a robust foundation for ongoing development, ensuring high standards of quality and reliability for the Restful Booker API. By adhering to best practices, this suite facilitates efficient testing and future expansion.
13 changes: 11 additions & 2 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ const { defineConfig } = require("cypress");

module.exports = defineConfig({
e2e: {
env: {
restfulBookerUrl: 'https://restful-booker.herokuapp.com'
},
chromeWebSecurity: false,
supportFile: 'cypress/support/commands.js',
specPattern: [
'cypress/integration/e2e/**/*.spec.js',
'cypress/integration/api/**/*.spec.js'
],
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
}
}
});
12 changes: 12 additions & 0 deletions cypress/fixtures/adBlockerUrls.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"blockAds": "https://pagead2.googlesyndication.com/**",
"blockGpt": "https://www.googletagservices.com/tag/js/gpt.js",
"blockGtm": "https://www.googletagmanager.com/gtm.js?id=GTM-MX8DD4S",
"blockAdPlus": "https://cdn.ad.plus/player/adplus.js",
"blockBacktrace": "https://events.backtrace.io/**",
"blockGif": "**/*.gif",
"blockUserMatch": "**/usermatch.gif**",
"blockMerge": "**/merge**",
"blockScripts": "**/*.js"
}

11 changes: 11 additions & 0 deletions cypress/fixtures/bookingDetails.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"firstname": "Jim",
"lastname": "Brown",
"totalprice": 111,
"depositpaid": true,
"bookingdates": {
"checkin": "2021-01-01",
"checkout": "2021-01-02"
},
"additionalneeds": "Breakfast"
}
36 changes: 36 additions & 0 deletions cypress/fixtures/credentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"users": {
"standardUser": {
"username": "standard_user",
"password": "secret_sauce"
},
"lockedOutUser": {
"username": "locked_out_user",
"password": "secret_sauce"
},
"problemUser": {
"username": "problem_user",
"password": "secret_sauce"
},
"performanceGlitchUser": {
"username": "performance_glitch_user",
"password": "secret_sauce"
},
"invalidUser": {
"username": "invalid_user",
"password": "secret_sauce"
},
"noPassword": {
"username": "standard_user",
"password": ""
},
"invalidPassword": {
"username": "standard_user",
"password": "invalid_password"
},
"noUsername": {
"username": "",
"password": "secret_sauce"
}
}
}
5 changes: 0 additions & 5 deletions cypress/fixtures/example.json

This file was deleted.

11 changes: 11 additions & 0 deletions cypress/fixtures/updateBookingDetails.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"firstname": "UpdatedFirstName",
"lastname": "UpdatedLastName",
"totalprice": 200,
"depositpaid": false,
"bookingdates": {
"checkin": "2023-01-10",
"checkout": "2023-01-15"
},
"additionalneeds": "Late checkout"
}
61 changes: 61 additions & 0 deletions cypress/integration/api/createBooking.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { getNewToken } from '../../support/utils';
import { compileSchema } from '../../support/ajv-utils';

describe('CreateBooking API Test', () => {
before(() => {
// Load and compile schemas
cy.readFile('cypress/schemas/createBookingRequest.json')
.then(compileSchema).as('validateRequest');
cy.readFile('cypress/schemas/createBookingResponse.json')
.then(compileSchema).as('validateResponse');
cy.log('Schemas compiled successfully.');

// Load booking details
cy.fixture('bookingDetails.json').as('bookingData');

// Retrieve a new token and store as alias
getNewToken().then(cy.wrap).as('token');
});

after(() => {
// Clean up: delete the booking created in the before hook
cy.get('@token').then(token => {
cy.get('@bookingId').then(bookingId => {
if (bookingId && token) {
cy.log('Cleaning up: deleting the booking created in the before hook');
cy.deleteBooking(bookingId, token).then(response => {
expect(response.status).to.eq(201);
cy.log(`Booking with ID: ${bookingId} deleted successfully.`);
});
} else {
cy.log('No booking ID or token available for cleanup.');
}
});
});
});

it('should create a new booking and validate the response matches the request', function () {
// Use aliases to ensure data is loaded before executing the test
cy.get('@token').then(token => {
cy.get('@bookingData').then(bookingData => {
cy.log('Creating a new booking with the provided details');
cy.createBooking(bookingData, token).then(response => {
expect(response.status).to.eq(200);
cy.log('Booking created with status:', response.status);

// Validate response schema
cy.get('@validateResponse').then(validateResponse => {
if (!validateResponse(response.body)) {
const errors = validateResponse.errors.map(err => `${err.instancePath} ${err.message}`).join(', ');
throw new Error(`Response validation failed: ${errors}`);
}
cy.log('Response schema validation passed.');

// Store the bookingId for cleanup
cy.wrap(response.body.bookingid).as('bookingId');
});
});
});
});
});
});
31 changes: 31 additions & 0 deletions cypress/integration/api/createToken.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { compileSchema } from '../../support/ajv-utils';

describe('CreateToken API Test', () => {
before(() => {
// Load and compile the schema, then store it as an alias for use in the tests
cy.readFile('cypress/schemas/createTokenResponse.json')
.then(compileSchema)
.as('validateTokenSchema'); // Storing the compiled schema as an alias
cy.log('Token schema compiled and stored as an alias.');
});

it('should create a new auth token', () => {
cy.apiRequest('POST', '/auth', null, {
username: 'admin',
password: 'password123',
}).then((response) => {
expect(response.status).to.eq(200);
cy.log('Auth token created, validating response...');

// Use the alias for the schema to validate the response
cy.get('@validateTokenSchema').then((validate) => {
const validationResult = validate(response.body);
if (!validationResult) {
const errors = validate.errors.map(err => `${err.instancePath} ${err.message}`).join(', ');
throw new Error(`Validation error: ${errors}`);
}
cy.log('Response validated successfully against the schema.');
});
});
});
});
47 changes: 47 additions & 0 deletions cypress/integration/api/deleteBooking.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { getNewToken } from '../../support/utils';
import { compileSchema } from '../../support/ajv-utils';

describe('Delete Booking by ID API Tests', () => {
let validateResponse, bookingId, token;

before(() => {
// Compile the response schema
cy.readFile('cypress/schemas/deleteBookingResponse.json')
.then(compileSchema)
.then((compiledSchema) => {
validateResponse = compiledSchema;
cy.log('Response schema compiled successfully.');
});

// Retrieve authentication token
getNewToken().then((receivedToken) => {
cy.wrap(receivedToken).as('token');
cy.log('Authentication token retrieved:', token);

// Load booking details from a fixture and create a booking
cy.fixture('bookingDetails.json').then((bookingDetails) => {
cy.createBooking(bookingDetails, token).then((response) => {
expect(response.status).to.eq(200);
bookingId = response.body.bookingid;
cy.wrap(bookingId).as('bookingId');
cy.log(`New booking created with ID: ${bookingId}`);
});
});
});
});

it('should delete a booking by ID', () => {
cy.get('@token').then((token) => {
cy.get('@bookingId').then((bookingId) => {
if (bookingId && token) {
cy.deleteBooking(bookingId, token).then(response => {
expect(response.status).to.eq(201);
cy.log(`Booking with ID: ${bookingId} deleted successfully.`);
});
} else {
cy.log('No booking ID or token available for cleanup.');
}
});
});
});
});
Loading