Skip to content

Commit

Permalink
Merge pull request #559 from bartoval/add_basic_auth_e2e
Browse files Browse the repository at this point in the history
test: ✅ Add support for e2e with auth basic
  • Loading branch information
bartoval authored Jan 21, 2025
2 parents 6f1859f + 1cab9d1 commit f91fbd0
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 69 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,19 @@ To run unit tests, use the following command:
yarn test
```

### Integration
### Local integration and e2e

To run integration tests, use the following command:
To run local integration tests, use the following command:

```bash
yarn cy
```

To run the e2e tests, you'll need to configure the following environment variables:

- `CYPRESS_BASE_URL`: This variable is used to specify the base URL of the application under test.
- `CYPRESS_USERNAME` and `CYPRESS_PASSWORD`: If your application requires Basic Authentication.

## Env variables

- `OBSERVER_URL`: The console uses a real network observer.
Expand Down
30 changes: 12 additions & 18 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import { defineConfig } from 'cypress';

const remoteUrl = process.env.CYPRESS_BASE_URL;

export default defineConfig({
e2e: {
baseUrl: process.env.CYPRESS_BASE_URL || 'http://localhost:3000',
chromeWebSecurity: false,
defaultCommandTimeout: 15000,
screenshotOnRunFailure: false,
video: false,
viewportHeight: 1080,
viewportWidth: 1920,
specPattern: (() => {
switch (process.env.TEST_TYPE) {
case 'e2e':
return 'cypress/e2e/**/*.cy.{ts,tsx}';
case 'local':
return 'cypress/local/**/*.cy.{ts,tsx}';
default:
return ['cypress/local/**/*.cy.{ts,tsx}', 'cypress/e2e/**/*.cy.{ts,tsx}'];
}
})()
}
baseUrl: remoteUrl || 'http://localhost:3000',
specPattern: remoteUrl ? 'cypress/e2e/**/*.cy.{ts,tsx}' : 'cypress/local/**/*.cy.{ts,tsx}'
},

defaultCommandTimeout: 15000,
screenshotOnRunFailure: false,
video: false,

viewportHeight: 1080,
viewportWidth: 1920
});
48 changes: 19 additions & 29 deletions cypress/e2e/api.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,63 @@ import { apiEndpoints } from '../../src/config/api';
describe('API Endpoint Tests', () => {
for (const [name, url] of Object.entries(apiEndpoints)) {
it(`Should GET ${name} (${url}) and verify the response`, () => {
cy.request('GET', url).as(`get${name}`);
cy.requestWithAuth('GET', url).as(`get${name}`);

cy.get(`@get${name}`).then((response: any) => {

Check warning on line 8 in cypress/e2e/api.cy.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Unexpected any. Specify a different type
expect(response.status).to.eq(200);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('count');
expect(response.body).to.have.property('timeRangeCount');
expect(response.body).to.have.property('results');

expect(response).to.have.property('headers');
expect(response.headers).to.have.property('content-type');
expect(response.headers['content-type']).to.contain('application/json');
});
});
}

it(`Should handle the Network error error for ${apiEndpoints.SITES}`, () => {
cy.intercept('GET', apiEndpoints.SITES, { forceNetworkError: true }).as(apiEndpoints.SITES);

cy.visit('/');

cy.wait(`@${apiEndpoints.SITES}`).then(() => {
cy.get(`body`).contains('ERR_NETWORK').should('be.visible');
it(`Should handle the Network error for ${apiEndpoints.SITES}`, () => {
cy.intercept('GET', apiEndpoints.SITES, { forceNetworkError: true }).as('networkError');
cy.visitWithAuth('/');
cy.wait('@networkError').then(() => {
cy.get('body').contains('ERR_NETWORK').should('be.visible');
});
});

it(`Should handle 500 error for ${apiEndpoints.SITES}`, () => {
cy.intercept('GET', apiEndpoints.SITES, { statusCode: 500 }).as(apiEndpoints.SITES);

cy.visit('/');

cy.wait(`@${apiEndpoints.SITES}`).its('response.statusCode').should('eq', 500);
cy.get(`body`).contains('500: Internal Server Error').should('be.visible');
cy.intercept('GET', apiEndpoints.SITES, { statusCode: 500 }).as('serverError');
cy.visitWithAuth('/');
cy.wait('@serverError').its('response.statusCode').should('eq', 500);
cy.get('body').contains('500: Internal Server Error').should('be.visible');
});

it(`Should handle 404 error for ${apiEndpoints.SITES}`, () => {
cy.intercept('GET', apiEndpoints.SITES, { statusCode: 404 }).as(apiEndpoints.SITES);

cy.visit('/');

cy.wait(`@${apiEndpoints.SITES}`).its('response.statusCode').should('eq', 404);
cy.get(`body`).contains('404: Not Found').should('be.visible');
cy.intercept('GET', apiEndpoints.SITES, { statusCode: 404 }).as('notFound');
cy.visitWithAuth('/');
cy.wait('@notFound').its('response.statusCode').should('eq', 404);
cy.get('body').contains('404: Not Found').should('be.visible');
});
});

describe('API Resilience Tests', () => {
it('Should recover after temporary service unavailability, clicking on Try again button', () => {
cy.intercept('GET', apiEndpoints.SITES, { forceNetworkError: true }).as(apiEndpoints.SITES);
cy.visit('/');
cy.get(`body`).contains('ERR_NETWORK').should('be.visible');
cy.intercept('GET', apiEndpoints.SITES, { forceNetworkError: true }).as('initialError');
cy.visitWithAuth('/');
cy.get('body').contains('ERR_NETWORK').should('be.visible');

cy.intercept('GET', apiEndpoints.SITES, { forceNetworkError: false }).as('secondTry');

cy.get(`body`).contains('Try again').should('be.visible').click();

cy.get('body').contains('Try again').should('be.visible').click();
cy.wait('@secondTry').its('response.statusCode').should('eq', 200);
});
});

describe('API Concurrency Tests', () => {
it('Should handle multiple concurrent requests', () => {
const endpoints = Object.values(apiEndpoints);

const requests = endpoints.map(
(url) =>
new Cypress.Promise((resolve) => {
cy.request('GET', url).then(resolve);
cy.requestWithAuth('GET', url).then(resolve);
})
);

Expand Down
54 changes: 36 additions & 18 deletions cypress/e2e/navigation-consistency.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,65 @@ const componentsPath = `/#${ComponentRoutesPaths.Components}`;
const processesPath = `/#${ProcessesRoutesPaths.Processes}`;

describe('Data Consistency Tests', () => {
it('Should maintain data consistency across sites and site detail', () => {
let data;

it('Should handle sites data and details correctly', () => {
cy.intercept('GET', apiEndpoints.SITES).as('section');
cy.visitWithAuth(sitesPath);

cy.visit(sitesPath);
cy.wait('@section').then((interception) => {
const response = interception.response.body;
data = response.results[0];

cy.visit(`${sitesPath}/${data.name}@${data.identity}`);
if (!response.results || response.results.length === 0) {
cy.log('No sites data available');
expect(response.results).to.be.an('array');
expect(response.count).to.equal(0);

return;
}

const data = response.results[0];
cy.visitWithAuth(`${sitesPath}/${data.name}@${data.identity}`);
cy.get(`[data-testid=${getTestsIds.siteView(data.identity)}]`).should('be.visible');
});
});

it('Should maintain data consistency across components and component detail', () => {
let data;

it('Should handle components data and details correctly', () => {
cy.intercept('GET', `${apiEndpoints.COMPONENTS}*`).as('section');
cy.visitWithAuth(componentsPath);

cy.visit(componentsPath);
cy.wait('@section').then((interception) => {
const response = interception.response.body;
data = response.results[0];

cy.visit(`${componentsPath}/${data.name}@${data.identity}`);
if (!response.results || response.results.length === 0) {
cy.log('No components data available');
expect(response.results).to.be.an('array');
expect(response.count).to.equal(0);

return;
}

const data = response.results[0];
cy.visitWithAuth(`${componentsPath}/${data.name}@${data.identity}`);
cy.get(`[data-testid=${getTestsIds.componentView(data.identity)}]`).should('be.visible');
});
});

it('Should maintain data consistency across processes and process detail', () => {
let data;

it('Should handle processes data and details correctly', () => {
cy.intercept('GET', `${apiEndpoints.PROCESSES}*`).as('section');
cy.visitWithAuth(processesPath);

cy.visit(processesPath);
cy.wait('@section').then((interception) => {
const response = interception.response.body;
data = response.results[0];

cy.visit(`${processesPath}/${data.name}@${data.identity}`);
if (!response.results || response.results.length === 0) {
cy.log('No processes data available');
expect(response.results).to.be.an('array');
expect(response.count).to.equal(0);

return;
}

const data = response.results[0];
cy.visitWithAuth(`${processesPath}/${data.name}@${data.identity}`);
cy.get(`[data-testid=${getTestsIds.processView(data.identity)}]`).should('be.visible');
});
});
Expand Down
32 changes: 32 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const getAuthConfig = () => {
const username = Cypress.env('USERNAME');
const password = Cypress.env('PASSWORD');

if (username && password) {
return {
auth: {
username,
password
}
};
}

return {};
};

Cypress.Commands.add('visitWithAuth', (url: string = '/', options = {}) => {
cy.visit(url, {
...getAuthConfig(),
...options
});
});

Cypress.Commands.add('requestWithAuth', (method: string, url: string, options = {}) => {
const authConfig = getAuthConfig();
cy.request({
method,
url,
...authConfig,
...options
}).as('requestResponse');
});
6 changes: 6 additions & 0 deletions cypress/support/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
declare namespace Cypress {
interface Chainable {
visitWithAuth(url?: string, options?: Record<string, unknown>): Chainable<null>;
requestWithAuth(method: string, url: string, options?: Record<string, unknown>): Chainable<null>;
}
}
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
"coverage": "yarn test --coverage",
"cy:dev": "cypress open",
"cy:run": "cypress run",
"ci": "TEST_TYPE=local start-test 3000 cy:run",
"ci:e2e": "TEST_TYPE=e2e cypress run",
"ci": "if [ -z \"$CYPRESS_BASE_URL\" ]; then start-test 3000 cy:run; else yarn cy:run; fi",
"lint": "TIMING=1 eslint --cache",
"lint-fix": "yarn lint --fix",
"format": "prettier --write '*/**/*.{ts,tsx,json,css}'",
Expand Down

0 comments on commit f91fbd0

Please sign in to comment.