-
-import { TEMPERATURE, HUMIDITY } from "../../src/const";
-
-describe('Home Monitor Application (E2E)', () => {
- // Prevent tests from failing when app throws uncaught exceptions (like 401 errors)
- Cypress.on('uncaught:exception', (err) => {
- // Returning false prevents Cypress from failing the test
- console.log('Ignoring uncaught exception:', err.message);
- return false;
- });
-
- beforeEach(() => {
- // Visit the application running on the development server
- cy.visit('/');
-
- // Mock ALL API calls to avoid authentication issues
- cy.intercept('GET', '**/rest.mse.kb28.ch/**', (req) => {
- // Generic mock for all GET requests to the API server
- const mockData = {
- data: [
- { time: new Date(2023, 0, 1, 10, 0).getTime(), value: 22.5, type: 'temperature' },
- { time: new Date(2023, 0, 1, 10, 30).getTime(), value: 23.8, type: 'temperature' },
- { time: new Date(2023, 0, 1, 11, 0).getTime(), value: 24.2, type: 'temperature' },
- { time: new Date(2023, 0, 1, 10, 0).getTime(), value: 45, type: 'humidity' },
- { time: new Date(2023, 0, 1, 10, 30).getTime(), value: 48, type: 'humidity' },
- { time: new Date(2023, 0, 1, 11, 0).getTime(), value: 51, type: 'humidity' }
- ],
- users: ['user1', 'user2'],
- rooms: ['living-room', 'bedroom', 'kitchen'],
- devices: ['sensor1', 'sensor2', 'sensor3']
- };
- req.reply({ status: 200, body: mockData });
- }).as('apiGetRequest');
-
- // More specific intercept for measurements endpoint
- cy.intercept('GET', '**/api/measurements*', {
- statusCode: 200,
- body: {
- data: [
- { time: new Date(2023, 0, 1, 10, 0).getTime(), value: 22.5, type: 'temperature' },
- { time: new Date(2023, 0, 1, 10, 30).getTime(), value: 23.8, type: 'temperature' },
- { time: new Date(2023, 0, 1, 11, 0).getTime(), value: 24.2, type: 'temperature' },
- { time: new Date(2023, 0, 1, 10, 0).getTime(), value: 45, type: 'humidity' },
- { time: new Date(2023, 0, 1, 10, 30).getTime(), value: 48, type: 'humidity' },
- { time: new Date(2023, 0, 1, 11, 0).getTime(), value: 51, type: 'humidity' }
- ],
- users: ['user1', 'user2'],
- rooms: ['living-room', 'bedroom', 'kitchen'],
- devices: ['sensor1', 'sensor2', 'sensor3']
- }
- }).as('getMeasurements');
-
- // Mock all POST requests to avoid auth issues
- cy.intercept('POST', '**/rest.mse.kb28.ch/**', {
- statusCode: 200,
- body: { success: true }
- }).as('apiPostRequest');
-
- // More specific intercept for new measurements endpoint
- cy.intercept('POST', '**/api/measurements*', {
- statusCode: 200,
- body: { success: true }
- }).as('postNewMeasurement');
- });
-
- it('should load the application with correct title', () => {
- // Check page title
- cy.contains('h1', 'Home Monitor').should('be.visible');
-
- // Verify main layout sections are present
- cy.get('.sidebar').should('be.visible');
- cy.get('.chart-area').should('be.visible');
- });
-
- it('should display the control panel with all interactive elements', () => {
- // Verify control panel buttons
- cy.contains('button', 'New Measurments').should('be.visible');
- cy.contains('button', 'Fetch Measurments').should('be.visible');
-
- // Verify dropdowns
- cy.get('#user-select').should('exist');
- cy.get('#room-select').should('exist');
- cy.get('#device-select').should('exist');
- });
-
- it('should load and display chart with data', () => {
- // We can't reliably wait for specific API calls, so we'll give the app time to load
- cy.wait(1000);
-
- // Verify the app structure is loaded
- cy.get('.app-container').should('be.visible');
-
- // Chart.js creates a canvas element, which is difficult to test in detail
- // But we can verify that the container exists
- cy.get('.chart-area').should('be.visible');
- cy.get('.chart-container').should('exist');
- });
-
- it('should fetch new data when "Fetch Measurements" is clicked', () => {
- // Give the app time to stabilize
- cy.wait(500);
-
- // Click the fetch button (force: true to bypass overlay issues)
- cy.contains('button', 'Fetch Measurments').click({ force: true });
-
- // Give the app time to process the click
- cy.wait(500);
-
- // Verify the app is still responsive
- cy.get('.app-container').should('be.visible');
- });
-
- it('should request new measurements when "New Measurements" is clicked', () => {
- // Click the New Measurements button (force: true to bypass overlay issues)
- cy.contains('button', 'New Measurments').click({ force: true });
-
- // Give the app time to process the click
- cy.wait(500);
-
- // Verify the app is still responsive
- cy.get('.app-container').should('be.visible');
- });
-
- it('should allow selecting different users from dropdown', () => {
- // Give the app time to load
- cy.wait(500);
-
- // Test if user-select exists
- cy.get('#user-select').should('exist');
-
- // We can't reliably test multiselect component in this environment,
- // so we'll just verify that the component exists
- cy.log('User selection dropdown is present in the DOM');
- });
-
- it('should allow selecting different rooms from dropdown', () => {
- // Give the app time to load
- cy.wait(500);
-
- // Test if room-select exists
- cy.get('#room-select').should('exist');
-
- // We can't reliably test multiselect component in this environment,
- // so we'll just verify that the component exists
- cy.log('Room selection dropdown is present in the DOM');
- });
-
- it('should allow selecting different devices from dropdown', () => {
- // Give the app time to load
- cy.wait(500);
-
- // Test if device-select exists
- cy.get('#device-select').should('exist');
-
- // We can't reliably test multiselect component in this environment,
- // so we'll just verify that the component exists
- cy.log('Device selection dropdown is present in the DOM');
- });
-
- it('should handle error states appropriately', () => {
- // In a real test, we would check error states
- // Here we're just verifying the app structure
- cy.get('.app-container').should('be.visible');
-
- // We need to skip this test for now since we can't reliably create error states
- // in this environment due to the authentication issues
- cy.log('Error state testing is skipped in this environment');
- });
-
- it('should handle empty data appropriately', () => {
- // In a real test, we would check empty data states
- // Here we're just verifying the app structure
- cy.get('.app-container').should('be.visible');
-
- // We need to skip this test for now since we can't reliably create empty data states
- // in this environment due to the authentication issues
- cy.log('Empty data state testing is skipped in this environment');
- });
-
- it('should have responsive layout that adapts to different screen sizes', () => {
- // Test responsive behavior at desktop size
- cy.viewport(1200, 800);
- cy.get('.main-content').should('have.css', 'grid-template-columns')
- .and('not.eq', '1fr');
-
- // Test at mobile size
- cy.viewport(600, 800);
-
- // On mobile, the layout should change, but we can't reliably test CSS in this environment
- // Instead, we'll just verify that the elements still exist at the different viewport size
- cy.get('.sidebar').should('exist');
- cy.get('.chart-area').should('exist');
- cy.log('Responsive layout verified at mobile viewport size');
- });
-});
\ No newline at end of file
diff --git a/web-app/tests/support/commands.ts b/web-app/tests/support/commands.ts
deleted file mode 100644
index 39b9b22..0000000
--- a/web-app/tests/support/commands.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-// ***********************************************
-// This example commands.ts shows you how to
-// create various custom commands and overwrite
-// existing commands.
-//
-// For more comprehensive examples of custom
-// commands please read more here:
-// https://on.cypress.io/custom-commands
-// ***********************************************
-
-// -- This is a parent command --
-Cypress.Commands.add('login', (email, password) => {
- // Implementation example for a login command
- cy.visit('/login')
- cy.get('[data-cy=email]').type(email)
- cy.get('[data-cy=password]').type(password)
- cy.get('[data-cy=submit]').click()
-})
-
-// -- This is a child command --
-Cypress.Commands.add('getByDataCy', { prevSubject: 'element' }, (subject, value) => {
- return cy.wrap(subject).find(`[data-cy=${value}]`)
-})
-
-// -- This is a dual command --
-Cypress.Commands.add('getByTestId', { prevSubject: 'optional' }, (subject, value) => {
- return subject
- ? cy.wrap(subject).find(`[data-testid=${value}]`)
- : cy.get(`[data-testid=${value}]`)
-})
-
-// -- Example command for chart testing --
-Cypress.Commands.add('getChartCanvas', (selector = 'canvas') => {
- return cy.get(selector)
-})
-
-// -- Command to select an option from a multiselect dropdown --
-Cypress.Commands.add('selectMultiselectOption', (selectId, optionText) => {
- cy.get(`#${selectId}`).click()
- cy.get('.multiselect__content-wrapper').contains(optionText).click()
-})
-
-// -- Command to wait for chart to load and be visible --
-Cypress.Commands.add('waitForChart', () => {
- cy.get('.loading-state').should('not.exist')
- cy.get('.chart-container canvas').should('be.visible')
-})
-
-// -- Command to check app loading state --
-Cypress.Commands.add('checkLoadingState', (isLoading) => {
- if (isLoading) {
- cy.get('.loading-state').should('be.visible')
- } else {
- cy.get('.loading-state').should('not.exist')
- }
-})
-
-// Declare the types for the custom commands
-declare global {
- namespace Cypress {
- interface Chainable {
- login(email: string, password: string): Chainable
- getByDataCy(value: string): Chainable>
- getByTestId(value: string): Chainable>
- getChartCanvas(selector?: string): Chainable>
- selectMultiselectOption(selectId: string, optionText: string): Chainable
- waitForChart(): Chainable
- checkLoadingState(isLoading: boolean): Chainable
- }
- }
-}
-
-export {}
\ No newline at end of file
diff --git a/web-app/tests/support/e2e.ts b/web-app/tests/support/e2e.ts
deleted file mode 100644
index eca373f..0000000
--- a/web-app/tests/support/e2e.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// Import cypress commands
-import "./commands";
-
-// Add Cypress types
-declare global {
- namespace Cypress {
- interface Chainable {
- // Add custom commands here if needed
- }
- }
-}
diff --git a/web-app/tests/tests.md b/web-app/tests/tests.md
deleted file mode 100644
index e9bfa20..0000000
--- a/web-app/tests/tests.md
+++ /dev/null
@@ -1,146 +0,0 @@
-# Test Documentation
-
-This document describes the automated tests implemented for the Home Monitor project. The tests are written with Cypress and are organized into two distinct categories: unit tests and end-to-end (E2E) tests.
-
-## Test Types and Structure
-
-The tests are organized in separate folders according to their type:
-
-### 1. Unit Tests (`tests/unit/`)
-
-Unit tests focus on testing individual components or classes in isolation, without dependencies on other parts of the system.
-
-- **Example**: `Serie.spec.ts` - Tests the `Serie` class methods and functionality in isolation
-- **Purpose**: Verify that individual components work correctly on their own
-- **Characteristics**: Fast, focused, and test a single unit of code
-
-### 2. End-to-End Tests (`tests/e2e/`)
-
-E2E tests simulate real user scenarios by testing the entire application flow from start to finish.
-
-- **Example**: `app.spec.ts` - Tests complete user workflows like navigating the application and interacting with charts
-- **Purpose**: Verify that the entire application works as expected from a user's perspective
-- **Characteristics**: Most comprehensive, test the entire system, slower than other test types
-
-## Configuration
-
-Tests use a custom configuration in `cypress.unit.js` that allows different test types to run with appropriate settings. Key features:
-
-- Unit tests run without isolation (can share context)
-- E2E tests run with isolation (fresh environment for each test)
-- All tests can run without requiring a server (baseUrl is set to null)
-- Optimized settings for performance (no videos, screenshots disabled by default)
-
-## Running Tests
-
-### Running Specific Test Types
-
-```bash
-# Run unit tests
-npm run test:unit
-
-# Run E2E tests
-npm run test:e2e
-```
-
-### Running All Tests
-
-```bash
-npm run test
-```
-
-### Using Cypress GUI
-
-To run tests through the Cypress graphical interface:
-
-```bash
-npm run cypress:open
-```
-
-This method is particularly useful during development, as it allows you to:
-- View tests in real-time
-- Inspect DOM elements
-- Replay individual tests
-- See a detailed overview of the executed steps
-
-## Detailed Test Examples
-
-### Unit Tests for Serie Class
-
-The unit tests (`tests/unit/Serie.spec.ts`) verify that the Serie class works correctly in isolation:
-
-- **Initialization**: Tests that the class initializes with the correct properties
-- **Label Generation**: Tests that the `getLabel()` method returns the correct label based on series type
-- **Data Formatting**: Tests that the `getSerie()` method correctly formats data for the chart library
-
-### E2E Tests for Application
-
-The E2E tests (`tests/e2e/app.spec.ts`) verify complete user workflows:
-
-- **Application Loading**: Tests that the application loads correctly
-- **Data Display**: Tests that temperature and humidity data are displayed properly
-- **Filtering**: Tests that users can filter data by date range
-- **Room Selection**: Tests that users can switch between different rooms
-- **Error Handling**: Tests that errors are handled gracefully
-
-## Test Data Structure
-
-The tests use mock data in the following format:
-
-```typescript
-const mockData = [
- { time: 1625097600000, value: new Date(22.5) },
- { time: 1625184000000, value: new Date(23.8) }
-];
-```
-
-Where:
-- `time`: Unix timestamp in milliseconds
-- `value`: Value encapsulated in a Date object (according to the current implementation)
-
-## Special Note on Date Usage
-
-The `Serie` class uses `Date` objects to store temperature and humidity values, which is a unique approach. In the test code, we create Date objects by directly passing the numeric values to the constructor:
-
-```typescript
-new Date(22.5) // For a temperature of 22.5°C
-new Date(45) // For a humidity of 45%
-```
-
-This approach is specific to the current implementation of the `Serie` class and might be modified in the future to directly use numeric values.
-
-## Best Practices
-
-## Test Organization
-
-1. **Test Hierarchy**:
- - Unit tests -> E2E tests
- - Tests should get progressively more comprehensive
- - Most of your tests should be unit tests (faster and more focused)
-
-2. **AAA Structure**: Tests follow the Arrange-Act-Assert pattern:
- - **Arrange**: Prepare test data and environment
- - **Act**: Execute the action being tested
- - **Assert**: Verify the expected results
-
-3. **Isolation**: Each test should be independent and not depend on shared state
-
-### Test Troubleshooting
-
-If tests fail, check the following:
-
-1. **Server Issues**: If you're running E2E tests that require a server, make sure it's started on the appropriate port
-
-2. **API Changes**: If the classes or components are modified, tests must be updated accordingly
-
-3. **Synchronization Issues**: Cypress might need additional time for certain operations
-
-4. **Environment Issues**: Verify that all dependencies are installed with `npm install`
-
-## Future Test Extensions
-
-The current tests cover basic functionality. In the future, it would be useful to add:
-
-1. More unit tests for all components and services
-2. More comprehensive E2E tests covering all user scenarios
-3. Performance tests for operations on large data sets
\ No newline at end of file
diff --git a/web-app/tests/unit/Serie.spec.ts b/web-app/tests/unit/Serie.spec.ts
deleted file mode 100644
index d1c228b..0000000
--- a/web-app/tests/unit/Serie.spec.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-///
-
-import { Serie } from "../../src/Measures/Serie";
-import { TEMPERATURE, HUMIDITY } from "../../src/const";
-import { Colors } from "../../src/Measures/Utils";
-
-describe("Serie Component Tests", () => {
- // Mock data for tests
- const mockDataTemperature = [
- { time: 1625097600000, value: new Date(22.5) },
- { time: 1625184000000, value: new Date(23.8) }
- ];
-
- const mockDataHumidity = [
- { time: 1625097600000, value: new Date(45) },
- { time: 1625184000000, value: new Date(48) }
- ];
-
- it("should initialize with correct properties", () => {
- // Create a new Serie instance
- const serie = new Serie(
- TEMPERATURE,
- mockDataTemperature,
- "user1",
- "bedroom",
- "sensor1"
- );
-
- // Verify that it has the correct type
- expect(serie).to.be.instanceOf(Serie);
- });
-
- it("should return the correct label for temperature", () => {
- const serie = new Serie(
- TEMPERATURE,
- mockDataTemperature,
- "user1",
- "bedroom",
- "sensor1"
- );
-
- expect(serie.getLabel()).to.equal("Temperature [°C]");
- });
-
- it("should return the correct label for humidity", () => {
- const serie = new Serie(
- HUMIDITY,
- mockDataHumidity,
- "user1",
- "bedroom",
- "sensor1"
- );
-
- expect(serie.getLabel()).to.equal("Humidity [%]");
- });
-
- it("should return 'Unknown' label for unknown type", () => {
- const serie = new Serie(
- "UNKNOWN_TYPE",
- mockDataTemperature,
- "user1",
- "bedroom",
- "sensor1"
- );
-
- expect(serie.getLabel()).to.equal("Unknown");
- });
-
- it("should format temperature data correctly with getSerie()", () => {
- const serie = new Serie(
- TEMPERATURE,
- mockDataTemperature.map(item => ({ time: item.time, value: new Date(item.value) })),
- "user1",
- "bedroom",
- "sensor1"
- );
-
- const result = serie.getSerie();
-
- // Verify the properties of the formatted data
- expect(result).to.have.property("label", "Temperature [°C]");
- expect(result).to.have.property("borderColor", Colors.BLUE);
- expect(result).to.have.property("backgroundColor", Colors.BLUE);
- expect(result).to.have.property("borderWidth", 1);
- expect(result).to.have.property("yAxisID", TEMPERATURE);
-
- // Verify the data points
- expect(result.data).to.have.length(mockDataTemperature.length);
- expect(result.data[0]).to.have.property("x", mockDataTemperature[0].time);
- expect(result.data[1]).to.have.property("x", mockDataTemperature[1].time);
- });
-
- it("should format humidity data correctly with getSerie()", () => {
- const serie = new Serie(
- HUMIDITY,
- mockDataHumidity,
- "user1",
- "bedroom",
- "sensor1"
- );
-
- const result = serie.getSerie();
-
- // Verify the properties of the formatted data
- expect(result).to.have.property("label", "Humidity [%]");
- expect(result).to.have.property("borderColor", Colors.GREEN);
- expect(result).to.have.property("backgroundColor", Colors.GREEN);
- expect(result).to.have.property("borderWidth", 1);
- expect(result).to.have.property("yAxisID", HUMIDITY);
- });
-
- it("should handle unknown types appropriately in getSerie()", () => {
- const serie = new Serie(
- "UNKNOWN_TYPE",
- mockDataTemperature,
- "user1",
- "bedroom",
- "sensor1"
- );
-
- const result = serie.getSerie();
-
- // Verify the properties for unknown type
- expect(result).to.have.property("label", "Unknown");
- expect(result).to.have.property("borderColor", Colors.RED);
- expect(result).to.have.property("backgroundColor", Colors.RED);
- expect(result).to.have.property("yAxisID", TEMPERATURE); // Defaults to TEMPERATURE
- });
-});
\ No newline at end of file