diff --git a/.env.template b/.env.template index 3cae7b0..e267436 100644 --- a/.env.template +++ b/.env.template @@ -7,4 +7,6 @@ MQTT_URL= MQTT_USERNAME= MQTT_PASSWORD= REST_USERNAME= -REST_PASSWORD= \ No newline at end of file +REST_PASSWORD= +REST_URL= +REST_PAGE= diff --git a/docker-compose.yml b/docker-compose.yml index de427aa..3547b33 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -109,8 +109,10 @@ services: - "8080:8080" environment: - - VUE_APP_INFLUXDB_USER=$REST_USERNAME - - VUE_APP_INFLUXDB_PASSWORD=$REST_PASSWORD + - VUE_APP_REST_USER=$REST_USERNAME + - VUE_APP_REST_PASSWORD=$REST_PASSWORD + - VUE_APP_REST_URL=$REST_URL + - VUE_APP_REST_PAGE=$REST_PAGE labels: - "traefik.enable=true" diff --git a/web-app/.gitlab-ci.yml b/web-app/.gitlab-ci.yml index 5fcd239..2969ba0 100644 --- a/web-app/.gitlab-ci.yml +++ b/web-app/.gitlab-ci.yml @@ -2,6 +2,11 @@ variables: DOCKER_IMAGE: registry.forge.hefr.ch/team-raclette/project-softweng/web-app:latest NODE_IMAGE: cypress/included:cypress-14.4.1-node-22.16.0-chrome-137.0.7151.68-1-ff-139.0.1-edge-137.0.3296.62-1 + VUE_APP_REST_USER: $REST_USER + VUE_APP_REST_PASSWORD: $REST_PASSWORD + VUE_APP_REST_URL: $REST_URL + VUE_APP_REST_PAGE: $TEST_PAGE + default: image: $DOCKER_IMAGE @@ -35,9 +40,10 @@ web-app-unit-tests: web-app-e2e-tests: image: $NODE_IMAGE stage: web-app-tests - services: - - name: $DOCKER_IMAGE - alias: app + + # services: + # - name: $DOCKER_IMAGE + # alias: app script: - echo "Running e2e tests" - apt-get update @@ -45,6 +51,6 @@ web-app-e2e-tests: - cd ./web-app - npm install --include=dev - echo "Wait web-app app is running" - - for i in {1..6}; do curl -f http://app:8080 && break || sleep 5; done - - echo "Flask app is running" + - for i in {1..6}; do curl -f https://app.mse.kb28.ch/ && break || sleep 5; done + - echo "App is running" - npm run test:e2e diff --git a/web-app/cypress.config.ts b/web-app/cypress.config.ts index 17161e3..6263ae2 100644 --- a/web-app/cypress.config.ts +++ b/web-app/cypress.config.ts @@ -5,5 +5,9 @@ export default defineConfig({ setupNodeEvents(on, config) { // implement node event listeners here }, + specPattern: [ + "cypress/e2e/*.cy.{js,jsx,ts,tsx}", + "cypress/unit/*.cy.{js,jsx,ts,tsx}", + ], }, }); diff --git a/web-app/cypress/e2e/fetch_process.cy.ts b/web-app/cypress/e2e/fetch_process.cy.ts index d95aa27..0e3cfc3 100644 --- a/web-app/cypress/e2e/fetch_process.cy.ts +++ b/web-app/cypress/e2e/fetch_process.cy.ts @@ -2,7 +2,7 @@ describe("Test fetch measurments button in the main page", () => { beforeEach(() => { - cy.visit("http://localhost:8080/"); + cy.visit("https://app.mse.kb28.ch"); }); it("Fetch timeseries with valid user-room-device", () => { diff --git a/web-app/cypress/e2e/serie.cy.ts b/web-app/cypress/unit/serie.cy.ts similarity index 100% rename from web-app/cypress/e2e/serie.cy.ts rename to web-app/cypress/unit/serie.cy.ts diff --git a/web-app/package.json b/web-app/package.json index a0a743a..4b529b6 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -7,7 +7,9 @@ "build": "vue-cli-service build", "cypress:open": "cypress open", "cypress:run": "cypress run", - "test": "cypress run --spec 'cypress/e2e/*.cy.ts'" + "test:e2e": "cypress run --spec 'cypress/e2e/*.cy.ts'", + "test:unit": "cypress run --spec 'cypress/unit/*.cy.ts'", + "test": "test:unit | test:e2e" }, "dependencies": { "axios": "^1.9.0", diff --git a/web-app/src/Services/HttpClient.ts b/web-app/src/Services/HttpClient.ts index 10fdde9..c019474 100644 --- a/web-app/src/Services/HttpClient.ts +++ b/web-app/src/Services/HttpClient.ts @@ -1,5 +1,5 @@ import axios, { AxiosResponse } from "axios"; -import { BASE, PING, RACLETTE, PONG } from "../const"; +import { BASE, PING, PAGE, PONG } from "../const"; export class HttpClient { private _url: string; @@ -45,7 +45,7 @@ export class HttpClient { room: string, device: string ): Promise> { - const response = await axios.get(`${BASE}${this._url}/${RACLETTE}`, { + const response = await axios.get(`${BASE}${this._url}/${PAGE}`, { headers: this.getAuthHeader(), params: { user: user, @@ -62,7 +62,7 @@ export class HttpClient { device: string ): Promise> { const response = await axios.post( - `${BASE}${this._url}/${RACLETTE}`, + `${BASE}${this._url}/${PAGE}`, { command: "MEASURE_NEW", }, diff --git a/web-app/src/const.ts b/web-app/src/const.ts index 7eb6d8e..f70cdd2 100644 --- a/web-app/src/const.ts +++ b/web-app/src/const.ts @@ -1,10 +1,10 @@ export const APP_NAME = "Home Monitor"; -export const URL = "rest.mse.kb28.ch"; +export const URL = process.env.VUE_APP_REST_URL; // load environment varaibles - need to have the prefix VUE_APP -export const USERNAME = process.env.VUE_APP_INFLUXDB_USER; -export const PASSWORD = process.env.VUE_APP_INFLUXDB_PASSWORD; +export const USERNAME = process.env.VUE_APP_REST_USER; +export const PASSWORD = process.env.VUE_APP_REST_PASSWORD; export const HUMIDITY = "humidity"; export const TEMPERATURE = "temperature"; @@ -17,5 +17,5 @@ export const DEVICE = "Shed"; export const BASE = "https://"; export const PING = "ping"; -export const RACLETTE = "raclette"; +export const PAGE = process.env.VUE_APP_REST_PAGE; export const PONG = "pong"; diff --git a/web-app/test.md b/web-app/test.md index 2e8c220..12b4df9 100644 --- a/web-app/test.md +++ b/web-app/test.md @@ -1,274 +1,43 @@ -# End-to-End Testing Documentation for Home Monitor +# End-to-End and Unit Testing Documentation for Home Monitor -## Table of Contents -- [Introduction](#introduction) -- [Testing Strategy](#testing-strategy) -- [Test Environment Setup](#test-environment-setup) -- [Running Tests](#running-tests) -- [Test Structure](#test-structure) -- [Test Cases Overview](#test-cases-overview) -- [Writing New Tests](#writing-new-tests) -- [Best Practices](#best-practices) -- [Troubleshooting](#troubleshooting) -- [References](#references) +## Test Description -## Introduction +The Home Monitor project uses Cypress to automate both End-to-End (E2E) and unit tests. These tests ensure that the main features of the application work correctly, both from the user’s and the developer’s perspectives. -End-to-End (E2E) testing verifies that the application functions correctly from a user's perspective by testing the complete application workflow. This document outlines the E2E testing approach for the Home Monitor application. +### Types of Tests -### Goals of E2E Testing +- **End-to-End (E2E) Tests**: Simulate real user behavior on the web interface. They check critical user flows, data display, error handling, and the responsiveness of the application. +- **Unit Tests**: Verify the correct functioning of JavaScript/TypeScript components and functions in isolation. -- Validate critical user flows function correctly -- Ensure components work together as expected -- Detect regression issues before production deployment -- Verify application behavior in real-world scenarios +### Test Structure -## Testing Strategy +- E2E tests are located in `web-app/cypress/e2e/` +- Unit tests are located in `web-app/cypress/unit/` +- Custom commands and global setup are in `web-app/cypress/support/` +- Cypress configuration is in `web-app/cypress.config.ts` -Home Monitor uses Cypress for E2E testing with two primary approaches: +### Example Scenarios Covered -1. **Mock Testing (Without Server)**: Fast, reliable tests using mocked DOM elements and data -2. **Real Environment Testing (With Server)**: Full application testing with a running development server +- Application loading and display of main sections +- Control panel functionality (buttons, filters) +- User, room, and device selection +- Display and update of measurement charts +- Handling of error or empty data states +- Responsive layout for mobile and desktop -### Mock vs. Real Testing Comparison - -| Aspect | Mock Testing | Real Environment Testing | -|--------|-------------|--------------------------| -| Speed | Very fast (< 1s per test) | Slower (depends on app loading time) | -| Reliability | Highly stable | May be affected by server/network issues | -| Coverage | Limited to structure and basic interactions | Tests actual rendering and behaviors | -| Dependencies | None (no server needed) | Requires development server | -| Best for | CI/CD, quick verification | Final validation, regression testing | - -## Test Environment Setup +## How to Run the Tests ### Prerequisites - Node.js (v14+) - npm or yarn -- Chrome browser (for visual testing) +- Chrome browser -### Installation +### Install Dependencies ```bash -# Install dependencies cd project-softweng/web-app npm install ``` -## Running Tests - -### Option 1: Tests with Mock Environment (No Server) - -```bash -# Run all tests in headless mode -export CYPRESS_SKIP_SERVER_CHECK=true -npm run test:e2e - -# Run specific test file -export CYPRESS_SKIP_SERVER_CHECK=true -npx cypress run --spec "tests/e2e/app.spec.ts" -``` - -### Option 2: Tests with Real Application (Server Required) - -#### Automated Script Method - -```bash -# Use the automated script (starts server, runs tests, stops server) -./tests/e2e/run-e2e-tests.sh -``` - -#### Manual Method - -1. Start the development server: - ```bash - # Terminal 1 - npm run serve - ``` - -2. Run the tests: - ```bash - # Terminal 2 - # Headless mode - npx cypress run --spec "tests/e2e/app.spec.ts" - - # Interactive mode - npx cypress open - ``` - -### Interactive Mode (Development) - -```bash -npm run cypress:open -``` - -This opens the Cypress Test Runner where you can: -- Select individual tests to run -- See test execution in real-time -- Debug failing tests with time-travel debugging - -## Test Structure - -### Directory Structure - -``` -web-app/ -├── tests/ -│ ├── e2e/ # E2E test files -│ │ ├── app.spec.ts # Main application tests -│ │ └── run-e2e-tests.sh # Script for running tests with server -│ └── support/ # Support files -│ ├── commands.ts # Custom Cypress commands -│ └── e2e.ts # Global setup for E2E tests -└── cypress.config.ts # Cypress configuration -``` - -### Test Files Organization - -Each test file follows this structure: -1. **Setup**: Import dependencies and set up the test environment -2. **Beforehooks**: Prepare the application state before each test -3. **Test Cases**: Individual test scenarios grouped by feature -4. **Helper Functions**: Support functions for test cases - -## Test Cases Overview - -The E2E test suite covers the following scenarios: - -1. **Application Loading** - - Verify application loads with correct title - - Confirm main layout sections are visible - -2. **Control Panel Functionality** - - Verify control panel buttons are present - - Test "Fetch Measurements" button works - - Test "New Measurements" button works - -3. **Filtering Controls** - - Test user selection dropdown - - Test room selection dropdown - - Test device selection dropdown - -4. **Data Visualization** - - Verify chart displays correctly - - Test chart updates when data changes - -5. **Error Handling** - - Test error state display - - Test empty data state display - -6. **Responsive Design** - - Verify layout adapts to desktop viewport - - Verify layout adapts to mobile viewport - -## Writing New Tests - -### Adding a New Test Case - -1. Identify the feature or flow to test -2. Determine the expected behavior -3. Add a new test case to the appropriate spec file: - -```typescript -it('should [describe expected behavior]', () => { - // Setup any preconditions - - // Perform actions - - // Assert expected outcomes -}); -``` - -### Custom Commands - -Custom commands are available to simplify test writing: - -```typescript -// Select an option from a multiselect dropdown -cy.selectMultiselectOption('user-select', 'user1'); - -// Wait for chart to load and be visible -cy.waitForChart(); - -// Check application loading state -cy.checkLoadingState(false); -``` - -### API Mocking - -Use Cypress's intercept feature to mock API responses: - -```typescript -// Mock GET request -cy.intercept('GET', '**/api/measurements*', { - statusCode: 200, - body: { - data: [ - { time: new Date(2023, 0, 1, 10, 0).getTime(), value: 22.5, type: 'temperature' } - ] - } -}).as('getMeasurements'); - -// Wait for the intercepted request -cy.wait('@getMeasurements'); -``` - -## Best Practices - -1. **Test Independence** - - Each test should be able to run independently - - Avoid dependencies between tests - - Reset state between tests - -2. **Selector Strategy** - - Prefer data attributes for test selectors (e.g., `data-cy`, `data-testid`) - - Avoid using CSS classes that might change with styling updates - - Establish a consistent selector naming convention - -3. **Handling Asynchronous Operations** - - Use explicit waits rather than arbitrary timeouts - - Wait for specific elements or network requests rather than fixed delays - - Handle loading states appropriately - -4. **Test Data Management** - - Use consistent test data - - Mock external dependencies - - Consider using fixtures for complex data structures - -5. **Error Handling** - - Add proper error handling in tests - - Use `Cypress.on('uncaught:exception')` for expected application errors - -## Troubleshooting - -### Common Issues and Solutions - -| Issue | Solution | -|-------|----------| -| Tests fail with 401 errors | Add `Cypress.on('uncaught:exception', () => false)` to handle authentication errors | -| Elements not found | Increase timeouts or check selectors; ensure elements are in the DOM | -| Click actions failing | Use `{ force: true }` option if elements might be covered by overlays | -| Tests passing locally but failing in CI | Check environment differences; ensure CI has all required dependencies | -| Timeouts on waiting for elements | Increase `defaultCommandTimeout` in cypress.config.ts | - -### Debugging Strategies - -1. **Use Cypress's Debug Tools** - - Add `.debug()` to pause execution at a specific point - - Use the time-travel debugger in interactive mode - -2. **Add Logging** - - Use `cy.log()` to add informative messages in the test - - Check browser console for application errors - -3. **Visualize Test State** - - Enable screenshots and videos for failed tests - - Use `cy.screenshot()` at critical points - -## References - -- [Cypress Documentation](https://docs.cypress.io/) -- [Vue Test Utils](https://vue-test-utils.vuejs.org/) -- [Testing Library](https://testing-library.com/) -- [Cypress Best Practices](https://docs.cypress.io/guides/references/best-practices) \ No newline at end of file +### Run unit Tests