From 19b19e4b1a75a0bfca72e436890e7ea275ded193 Mon Sep 17 00:00:00 2001 From: Hamed Valiollahi Bayeki Date: Thu, 5 Dec 2024 08:23:44 -0800 Subject: [PATCH 1/3] feat: implement startsWith filter for number columns --- .../tests/fuel_code/test_fuel_code_repo.py | 143 ++++++++++++++++-- .../tests/fuel_code/test_fuel_code_service.py | 4 +- backend/lcfs/web/api/base.py | 3 + backend/lcfs/web/api/fuel_code/__init__.py | 2 +- backend/lcfs/web/api/fuel_code/repo.py | 53 +++++-- backend/lcfs/web/api/fuel_code/services.py | 56 ++++++- backend/lcfs/web/api/fuel_code/views.py | 1 - .../Admin/AdminMenu/components/_schema.js | 14 +- frontend/src/views/FuelCodes/_schema.jsx | 16 +- frontend/src/views/Transactions/_schema.js | 48 +++--- 10 files changed, 274 insertions(+), 66 deletions(-) diff --git a/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py b/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py index 1e72c4abd..6f0e4cc3a 100644 --- a/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py +++ b/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py @@ -1,13 +1,44 @@ import pytest from unittest.mock import AsyncMock from lcfs.web.api.fuel_code.repo import FuelCodeRepository -from lcfs.db.models.fuel.TransportMode import TransportMode +from lcfs.db.models.fuel.FuelCode import FuelCode +from lcfs.db.models.fuel.FuelCodeStatus import FuelCodeStatus, FuelCodeStatusEnum +from lcfs.web.api.base import PaginationRequestSchema +from sqlalchemy.ext.asyncio import AsyncSession + + +# Custom mock classes to simulate SQLAlchemy result objects +class MockScalarsResult: + def __init__(self, data): + self.data = data + + def all(self): + return self.data + + +class MockUniqueResult: + def __init__(self, data): + self.data = data + + def scalars(self): + return MockScalarsResult(self.data) + + +class MockExecuteResult: + def __init__(self, data): + self.data = data + + def unique(self): + return MockUniqueResult(self.data) + + def scalar(self): + return self.data # Make scalar() a synchronous method @pytest.fixture def mock_db(): """Fixture for mocking the database session.""" - return AsyncMock() + return AsyncMock(spec=AsyncSession) @pytest.fixture @@ -19,20 +50,102 @@ def fuel_code_repo(mock_db): @pytest.mark.anyio -async def test_get_transport_mode_by_name(fuel_code_repo, mock_db): - # Define the test transport mode - transport_mode_name = "Truck" - mock_transport_mode = TransportMode(transport_mode_id=1, transport_mode="Truck") - - # Mock the database query result - mock_db.execute.return_value.scalar_one_or_none = AsyncMock() - mock_db.execute.return_value.scalar_one_or_none.return_value = mock_transport_mode +async def test_get_fuel_codes_paginated(fuel_code_repo, mock_db): + # Prepare mock data + fuel_code_1 = FuelCode(fuel_code_id=1, fuel_suffix="101.0", company="Company A") + fuel_code_2 = FuelCode(fuel_code_id=2, fuel_suffix="102.0", company="Company B") + fuel_codes = [fuel_code_1, fuel_code_2] + total_count = 2 + + # Mock the get_fuel_status_by_status method + delete_status = FuelCodeStatus( + fuel_code_status_id=99, status=FuelCodeStatusEnum.Deleted + ) + fuel_code_repo.get_fuel_status_by_status = AsyncMock(return_value=delete_status) + + # Use a counter to determine which call is the count query and which is the data query + call_count = 0 + + async def mock_execute(query): + nonlocal call_count + call_count += 1 + if call_count == 1: + # First call is the count query + return MockExecuteResult(total_count) + elif call_count == 2: + # Second call is the data query + return MockExecuteResult(fuel_codes) + else: + # Additional calls if any + return MockExecuteResult(None) + + mock_db.execute.side_effect = mock_execute + + # Prepare pagination and conditions + pagination = PaginationRequestSchema(page=1, size=10, sort_orders=[], filters=[]) + conditions = [FuelCode.company == "Company A"] # Example condition # Call the repository method - result = await fuel_code_repo.get_transport_mode_by_name(transport_mode_name) + result_fuel_codes, result_total_count = ( + await fuel_code_repo.get_fuel_codes_paginated(pagination, conditions) + ) + + # Assert that the result matches the expected output + assert result_fuel_codes == fuel_codes + assert result_total_count == total_count + + # Ensure the database query was called the expected number of times + assert mock_db.execute.call_count == 2 # Once for count, once for data + + # Check that get_fuel_status_by_status was called + fuel_code_repo.get_fuel_status_by_status.assert_called_once_with("Deleted") + + +@pytest.mark.anyio +async def test_get_fuel_codes_paginated_no_results(fuel_code_repo, mock_db): + # Mock data with no fuel codes + fuel_codes = [] + total_count = 0 + + # Mock the get_fuel_status_by_status method + delete_status = FuelCodeStatus( + fuel_code_status_id=99, status=FuelCodeStatusEnum.Deleted + ) + fuel_code_repo.get_fuel_status_by_status = AsyncMock(return_value=delete_status) + + # Use a counter to determine which call is the count query and which is the data query + call_count = 0 + + async def mock_execute(query): + nonlocal call_count + call_count += 1 + if call_count == 1: + # First call is the count query + return MockExecuteResult(total_count) + elif call_count == 2: + # Second call is the data query + return MockExecuteResult(fuel_codes) + else: + # Additional calls if any + return MockExecuteResult(None) + + mock_db.execute.side_effect = mock_execute + + # Prepare pagination and conditions + pagination = PaginationRequestSchema(page=1, size=10, sort_orders=[], filters=[]) + conditions = [FuelCode.company == "Non-Existent Company"] + + # Call the repository method + result_fuel_codes, result_total_count = ( + await fuel_code_repo.get_fuel_codes_paginated(pagination, conditions) + ) + + # Assert that the result is an empty list and total count is zero + assert result_fuel_codes == fuel_codes # Should be an empty list + assert result_total_count == total_count # Should be zero - # Assert the result matches the mock data - assert result == mock_transport_mode + # Ensure the database query was called the expected number of times + assert mock_db.execute.call_count == 2 # Once for count, once for data - # Ensure the database query was called - mock_db.execute.assert_called_once() \ No newline at end of file + # Check that get_fuel_status_by_status was called + fuel_code_repo.get_fuel_status_by_status.assert_called_once_with("Deleted") diff --git a/backend/lcfs/tests/fuel_code/test_fuel_code_service.py b/backend/lcfs/tests/fuel_code/test_fuel_code_service.py index d6d778bf3..1ed9e3470 100644 --- a/backend/lcfs/tests/fuel_code/test_fuel_code_service.py +++ b/backend/lcfs/tests/fuel_code/test_fuel_code_service.py @@ -40,7 +40,7 @@ async def test_get_fuel_codes_success(): ] repo_mock.get_fuel_codes_paginated.return_value = (mock_fuel_codes, 1) - pagination = PaginationRequestSchema(page=1, size=10) + pagination = PaginationRequestSchema(page=1, size=10, filters=[], sort_orders=[]) # Act result = await service.get_fuel_codes(pagination) @@ -49,7 +49,7 @@ async def test_get_fuel_codes_success(): assert isinstance(result.pagination, PaginationResponseSchema) assert len(result.fuel_codes) == 1 assert result.fuel_codes[0].company == "XYZ Corp" - repo_mock.get_fuel_codes_paginated.assert_called_once_with(pagination) + repo_mock.get_fuel_codes_paginated.assert_called_once_with(pagination, []) @pytest.mark.anyio diff --git a/backend/lcfs/web/api/base.py b/backend/lcfs/web/api/base.py index c8d09bde9..bcea89c96 100644 --- a/backend/lcfs/web/api/base.py +++ b/backend/lcfs/web/api/base.py @@ -21,9 +21,11 @@ class BaseSchema(BaseModel): from_attributes=True, ) + class ComplianceReportRequestSchema(BaseSchema): compliance_report_id: int + def row_to_dict(row, schema): d = {} for field in schema.__fields__.values(): @@ -222,6 +224,7 @@ def apply_number_filter_conditions(field, filter_value, filter_option): "greaterThanOrEqual": field >= int(filter_value), "lessThan": field < int(filter_value), "lessThanOrEqual": field <= int(filter_value), + "startsWith": cast(field, String).like(f"{filter_value}%"), } return number_filter_mapping.get(filter_option) diff --git a/backend/lcfs/web/api/fuel_code/__init__.py b/backend/lcfs/web/api/fuel_code/__init__.py index 51f29b311..45fe85147 100644 --- a/backend/lcfs/web/api/fuel_code/__init__.py +++ b/backend/lcfs/web/api/fuel_code/__init__.py @@ -1,4 +1,4 @@ -"""User API.""" +"""Fuel code API.""" from lcfs.web.api.fuel_code.views import router diff --git a/backend/lcfs/web/api/fuel_code/repo.py b/backend/lcfs/web/api/fuel_code/repo.py index 8eb686fea..75645bcc5 100644 --- a/backend/lcfs/web/api/fuel_code/repo.py +++ b/backend/lcfs/web/api/fuel_code/repo.py @@ -1,5 +1,5 @@ from datetime import date -from typing import List, Dict, Any, Union, Optional, Sequence, TypedDict +from typing import List, Dict, Any, Union, Optional, Sequence import structlog from fastapi import Depends @@ -25,7 +25,7 @@ from lcfs.db.models.fuel.TargetCarbonIntensity import TargetCarbonIntensity from lcfs.db.models.fuel.TransportMode import TransportMode from lcfs.db.models.fuel.UnitOfMeasure import UnitOfMeasure -from lcfs.web.api.base import PaginationRequestSchema +from lcfs.web.api.base import get_field_for_filter, PaginationRequestSchema from lcfs.web.api.fuel_code.schema import FuelCodeCloneSchema, FuelCodeSchema from lcfs.web.core.decorators import repo_handler from dataclasses import dataclass @@ -276,19 +276,18 @@ async def get_expected_use_type_by_name(self, name: str) -> ExpectedUseType: @repo_handler async def get_fuel_codes_paginated( - self, pagination: PaginationRequestSchema + self, pagination: PaginationRequestSchema, conditions: list ) -> tuple[Sequence[FuelCode], int]: """ - Queries fuel codes from the database with optional filters. Supports pagination and sorting. + Queries fuel codes from the database with optional filters and sorting. Args: - pagination (dict): Pagination and sorting parameters. + pagination (PaginationRequestSchema): Pagination and sorting parameters. + conditions (list): List of SQLAlchemy conditions to apply. Returns: - List[FuelCodeSchema]: A list of fuel codes matching the query. + Tuple containing a list of FuelCode instances and the total count. """ - conditions = [] - # TODO: Filtering and Sorting logic needs to be added. delete_status = await self.get_fuel_status_by_status("Deleted") # setup pagination offset = 0 if (pagination.page < 1) else (pagination.page - 1) * pagination.size @@ -310,14 +309,38 @@ async def get_fuel_codes_paginated( ) .where(FuelCode.fuel_status_id != delete_status.fuel_code_status_id) ) + + # Apply the conditions + if conditions: + query = query.where(and_(*conditions)) + + # Apply sorting + if pagination.sort_orders: + for order in pagination.sort_orders: + field_name = order.field + direction = order.direction + if field_name == "fuel_code": + # Handle sorting for 'fuel_code' field + field = func.concat( + FuelCode.fuel_code_prefix.prefix, FuelCode.fuel_suffix + ) + else: + field = get_field_for_filter(FuelCode, field_name) + if field is not None: + if direction.lower() == "asc": + query = query.order_by(field.asc()) + else: + query = query.order_by(field.desc()) + else: + # Default sorting + query = query.order_by(FuelCode.create_date.desc()) + # Execute the count query to get the total count count_query = query.with_only_columns(func.count()).order_by(None) total_count = (await self.db.execute(count_query)).scalar() # Execute the main query to retrieve all fuel codes - result = await self.db.execute( - query.offset(offset).limit(limit).order_by(FuelCode.create_date.desc()) - ) + result = await self.db.execute(query.offset(offset).limit(limit)) fuel_codes = result.unique().scalars().all() return fuel_codes, total_count @@ -684,7 +707,10 @@ async def get_fuel_code_by_name(self, fuel_code: str) -> FuelCode: result = await self.db.execute( select(FuelCode) .join(FuelCode.fuel_code_prefix) - .join(FuelCodeStatus, FuelCode.fuel_status_id == FuelCodeStatus.fuel_code_status_id) + .join( + FuelCodeStatus, + FuelCode.fuel_status_id == FuelCodeStatus.fuel_code_status_id, + ) .outerjoin(FuelType, FuelCode.fuel_type_id == FuelType.fuel_type_id) .options( contains_eager(FuelCode.fuel_code_prefix), @@ -693,7 +719,8 @@ async def get_fuel_code_by_name(self, fuel_code: str) -> FuelCode: ) .where( and_( - func.concat(FuelCodePrefix.prefix, FuelCode.fuel_suffix) == fuel_code, + func.concat(FuelCodePrefix.prefix, FuelCode.fuel_suffix) + == fuel_code, FuelCodeStatus.status != FuelCodeStatusEnum.Deleted, ) ) diff --git a/backend/lcfs/web/api/fuel_code/services.py b/backend/lcfs/web/api/fuel_code/services.py index 2a09c5e6d..62d121350 100644 --- a/backend/lcfs/web/api/fuel_code/services.py +++ b/backend/lcfs/web/api/fuel_code/services.py @@ -1,15 +1,18 @@ import math -from datetime import datetime import structlog from fastapi import Depends +from sqlalchemy import func from lcfs.db.models.fuel.FeedstockFuelTransportMode import FeedstockFuelTransportMode from lcfs.db.models.fuel.FinishedFuelTransportMode import FinishedFuelTransportMode from lcfs.db.models.fuel.FuelCode import FuelCode -from lcfs.db.models.fuel.FuelCodeStatus import FuelCodeStatus, FuelCodeStatusEnum +from lcfs.db.models.fuel.FuelCodeStatus import FuelCodeStatusEnum from lcfs.db.models.fuel.FuelType import QuantityUnitsEnum from lcfs.web.api.base import ( + get_field_for_filter, + apply_filter_conditions, + validate_pagination, PaginationRequestSchema, PaginationResponseSchema, ) @@ -114,24 +117,65 @@ async def get_fuel_codes( self, pagination: PaginationRequestSchema ) -> FuelCodesSchema: """ - Gets the list of fuel codes. + Gets the list of fuel codes with filtering and sorting. """ - fuel_codes, total_count = await self.repo.get_fuel_codes_paginated(pagination) + conditions = [] + pagination = validate_pagination(pagination) + if pagination.filters and len(pagination.filters) > 0: + self.apply_fuel_code_filters(pagination, conditions) + + fuel_codes, total_count = await self.repo.get_fuel_codes_paginated( + pagination, conditions + ) if len(fuel_codes) == 0: - raise DataNotFoundException("No fuel codes found") + fuel_codes = [] + total_count = 0 + return FuelCodesSchema( pagination=PaginationResponseSchema( total=total_count, page=pagination.page, size=pagination.size, - total_pages=math.ceil(total_count / pagination.size), + total_pages=( + math.ceil(total_count / pagination.size) if total_count > 0 else 1 + ), ), fuel_codes=[ FuelCodeSchema.model_validate(fuel_code) for fuel_code in fuel_codes ], ) + def apply_fuel_code_filters(self, pagination, conditions): + """ + Apply filters to the fuel codes query. + + Args: + pagination (PaginationRequestSchema): The pagination object containing page and size information. + conditions (List[Condition]): The list of conditions to apply. + """ + for filter in pagination.filters: + field_name = filter.field + filter_value = filter.filter + filter_type = filter.filter_type + filter_option = filter.type + + if field_name == "fuel_code": + # Handle the 'fuel_code' field, which is a combination of prefix and suffix + field = func.concat( + FuelCode.fuel_code_prefix.prefix, FuelCode.fuel_suffix + ) + else: + field = get_field_for_filter(FuelCode, field_name) + + if field is None: + # Skip if the field is not found + continue + + conditions.append( + apply_filter_conditions(field, filter_value, filter_option, filter_type) + ) + async def convert_to_model( self, fuel_code_schema: FuelCodeCreateUpdateSchema, status: FuelCodeStatusEnum ) -> FuelCode: diff --git a/backend/lcfs/web/api/fuel_code/views.py b/backend/lcfs/web/api/fuel_code/views.py index 4e49068c1..e05126e42 100644 --- a/backend/lcfs/web/api/fuel_code/views.py +++ b/backend/lcfs/web/api/fuel_code/views.py @@ -26,7 +26,6 @@ SearchFuelCodeList, TableOptionsSchema, FuelCodeSchema, - DeleteFuelCodeResponseSchema, ) from lcfs.web.api.fuel_code.services import FuelCodeServices from lcfs.web.core.decorators import view_handler diff --git a/frontend/src/views/Admin/AdminMenu/components/_schema.js b/frontend/src/views/Admin/AdminMenu/components/_schema.js index 23a63525f..5097ba120 100644 --- a/frontend/src/views/Admin/AdminMenu/components/_schema.js +++ b/frontend/src/views/Admin/AdminMenu/components/_schema.js @@ -166,7 +166,12 @@ export const userLoginHistoryColDefs = (t) => [ { field: 'userLoginHistoryId', headerName: t('admin:userLoginHistoryColLabels.userLoginHistoryId'), - cellDataType: 'number' + cellDataType: 'number', + filter: 'agNumberColumnFilter', + filterParams: { + filterOptions: ['startsWith'], + buttons: ['clear'] + } }, { field: 'keycloakEmail', @@ -234,7 +239,12 @@ export const auditLogColDefs = (t) => [ headerName: t('admin:auditLogColLabels.rowId'), minWidth: 100, sortable: true, - filter: 'agTextColumnFilter' + cellDataType: 'number', + filter: 'agNumberColumnFilter', + filterParams: { + filterOptions: ['startsWith'], + buttons: ['clear'] + } }, { colId: 'changedFields', diff --git a/frontend/src/views/FuelCodes/_schema.jsx b/frontend/src/views/FuelCodes/_schema.jsx index dc4e430ed..6e2e64c7e 100644 --- a/frontend/src/views/FuelCodes/_schema.jsx +++ b/frontend/src/views/FuelCodes/_schema.jsx @@ -14,7 +14,6 @@ import { NumberEditor } from '@/components/BCDataGrid/components' - export const fuelCodeColDefs = (t) => [ { field: 'status', @@ -31,13 +30,24 @@ export const fuelCodeColDefs = (t) => [ { field: 'fuelSuffix', headerName: t('fuelCode:fuelCodeColLabels.fuelSuffix'), - cellRenderer: TextRenderer + cellRenderer: TextRenderer, + type: 'numericColumn', + filter: 'agNumberColumnFilter', + filterParams: { + filterOptions: ['startsWith'], + buttons: ['clear'] + } }, { field: 'carbonIntensity', headerName: t('fuelCode:fuelCodeColLabels.carbonIntensity'), cellRenderer: TextRenderer, - type: 'numericColumn' + type: 'numericColumn', + filter: 'agNumberColumnFilter', + filterParams: { + filterOptions: ['startsWith'], + buttons: ['clear'] + } }, { field: 'edrms', diff --git a/frontend/src/views/Transactions/_schema.js b/frontend/src/views/Transactions/_schema.js index 9978771a7..46bbbc82c 100644 --- a/frontend/src/views/Transactions/_schema.js +++ b/frontend/src/views/Transactions/_schema.js @@ -2,7 +2,7 @@ import { numberFormatter, currencyFormatter, dateFormatter, - spacesFormatter, + spacesFormatter } from '@/utils/formatters' import { TransactionStatusRenderer } from '@/utils/grid/cellRenderers' import { BCColumnSetFilter } from '@/components/BCDataGrid/components' @@ -26,7 +26,7 @@ export const transactionsColDefs = (t) => [ return `${prefix}${params.data.transactionId}` }, filterParams: { - buttons:["clear"], + buttons: ['clear'] } }, { @@ -39,11 +39,11 @@ export const transactionsColDefs = (t) => [ textFormatter: (value) => value.replace(/\s+/g, '').toLowerCase(), textCustomComparator: (filter, value, filterText) => { // Remove spaces and convert both to lowercase for comparison - const cleanFilterText = filterText.replace(/\s+/g, '').toLowerCase(); - const cleanValue = value.replace(/\s+/g, '').toLowerCase(); - return cleanValue.includes(cleanFilterText); + const cleanFilterText = filterText.replace(/\s+/g, '').toLowerCase() + const cleanValue = value.replace(/\s+/g, '').toLowerCase() + return cleanValue.includes(cleanFilterText) }, - buttons:["clear"], + buttons: ['clear'] }, width: 222 }, @@ -54,7 +54,7 @@ export const transactionsColDefs = (t) => [ minWidth: 300, flex: 2, filterParams: { - buttons:["clear"], + buttons: ['clear'] } }, { @@ -64,7 +64,7 @@ export const transactionsColDefs = (t) => [ minWidth: 300, flex: 2, filterParams: { - buttons:["clear"], + buttons: ['clear'] } }, { @@ -76,7 +76,8 @@ export const transactionsColDefs = (t) => [ width: 140, filter: 'agNumberColumnFilter', filterParams: { - buttons:["clear"], + filterOptions: ['startsWith'], + buttons: ['clear'] } }, { @@ -86,12 +87,13 @@ export const transactionsColDefs = (t) => [ valueFormatter: currencyFormatter, width: 190, valueGetter: (params) => { - const value = params.data?.pricePerUnit; - return value !== null && value !== undefined ? value : null; + const value = params.data?.pricePerUnit + return value !== null && value !== undefined ? value : null }, filter: 'agNumberColumnFilter', filterParams: { - buttons:["clear"], + filterOptions: ['startsWith'], + buttons: ['clear'] } }, { @@ -122,20 +124,20 @@ export const transactionsColDefs = (t) => [ filterOptions: ['inRange', 'equals', 'lessThan', 'greaterThan'], defaultOption: 'inRange', comparator: (filterDate, cellValue) => { - const cellDate = new Date(cellValue).setHours(0, 0, 0, 0); - const filterDateOnly = new Date(filterDate).setHours(0, 0, 0, 0); + const cellDate = new Date(cellValue).setHours(0, 0, 0, 0) + const filterDateOnly = new Date(filterDate).setHours(0, 0, 0, 0) - if (cellDate < filterDateOnly) { - return -1; // Cell date is before the filter date - } else if (cellDate > filterDateOnly) { - return 1; // Cell date is after the filter date - } else { - return 0; // Dates are the same (ignoring time) - } + if (cellDate < filterDateOnly) { + return -1 // Cell date is before the filter date + } else if (cellDate > filterDateOnly) { + return 1 // Cell date is after the filter date + } else { + return 0 // Dates are the same (ignoring time) + } }, browserDatePicker: true, // Uses the browser's date picker if available - buttons:["clear"], - } + buttons: ['clear'] + } } ] From 1c422d3b7eef3f97de175c1c1c251e11877ce036 Mon Sep 17 00:00:00 2001 From: Daniel Haselhan Date: Fri, 6 Dec 2024 13:45:09 -0800 Subject: [PATCH 2/3] feat: Add Cypress test for entering FS * Expand existing cypress test to enter an FS and confirm the values show in the compliance report summary --- .../ComplianceReport/ComplianceReport.test.js | 83 +++++++++++++++++++ .../ComplianceReportManagement.feature | 4 + .../components/ActivityLinkList.jsx | 6 +- .../components/ComplianceReportSummary.jsx | 3 + .../components/SummaryTable.jsx | 1 + 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReport.test.js b/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReport.test.js index 7190e79a9..e175c8f20 100644 --- a/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReport.test.js +++ b/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReport.test.js @@ -30,6 +30,68 @@ When('the supplier creates a new compliance report', () => { cy.contains('.MuiList-root li', currentYear).click() }) +When('the supplier navigates to the fuel supply page', () => { + cy.get( + '[data-test="schedule-list"] > :nth-child(1) > .MuiTypography-root' + ).click() + + cy.contains('.MuiTypography-h5', 'Add new supply of fuel').should( + 'be.visible' + ) +}) + +When('the supplier enters a valid fuel supply row', () => { + // First, ensure the grid is loaded + cy.get('.ag-root').should('be.visible') + + cy.wait(1000) + + // Set "Fuel type" to "CNG" + cy.get('div[col-id="fuelType"][title="Select the fuel type from the list"]') + .click() + .find('input') + .type('CNG{enter}') + + cy.wait(800) + + // Set "Fuel category" to "Gasoline" + cy.get( + 'div[col-id="fuelCategory"][title="Select the fuel category from the list"]' + ) + .click() + .find('input') + .type('Gasoline{enter}') + cy.wait(800) + + // Set "Determining carbon intensity" to "Default carbon intensity - section 19 (b) (ii)" + cy.get( + 'div[col-id="provisionOfTheAct"][title="Act Relied Upon to Determine Carbon Intensity: Identify the appropriate provision of the Act relied upon to determine the carbon intensity of each fuel."]' + ).click() + + cy.get('body').click() + cy.contains('Row updated successfully.').should('be.visible') + cy.wait(700) + cy.get('.ag-body-horizontal-scroll-viewport').scrollTo(1000, 0) + cy.wait(1200) + + // Set "Quantity" to "10,000" + cy.get('div.ag-cell[col-id="quantity"]') + .click() + .wait(1200) + .find('input') + .type('10000{enter}') + + cy.contains('Row updated successfully.').should('be.visible') +}) + +When('saves and returns to the report', () => { + cy.get('.MuiButton-contained').click() + + cy.get('[data-test="compliance-report-status"]') + .should('be.visible') + .and('have.text', 'Status: Draft') +}) + Then('the compliance report introduction is shown', () => { // Assert the header cy.get('[data-test="compliance-report-header"]') @@ -57,3 +119,24 @@ Then('the compliance report introduction is shown', () => { 'Welcome to the British Columbia Low Carbon Fuel Standard Portal' ) }) + +Then('the compliance report summary includes the quantity', () => { + cy.wait(2000) + cy.get( + '[data-test="renewable-summary"] > .MuiTable-root > .MuiTableBody-root > :nth-child(2) > :nth-child(3) > span' + ) + .should('be.visible') + .and('have.text', '10,000') + + cy.get( + '[data-test="renewable-summary"] > .MuiTable-root > .MuiTableBody-root > :nth-child(3) > :nth-child(3) > span' + ) + .should('be.visible') + .and('have.text', '10,000') + + cy.get( + '[data-test="renewable-summary"] > .MuiTable-root > .MuiTableBody-root > :nth-child(4) > :nth-child(3) > span' + ) + .should('be.visible') + .and('have.text', '500') +}) diff --git a/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReportManagement.feature b/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReportManagement.feature index 01361dcff..a0e9c1975 100644 --- a/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReportManagement.feature +++ b/frontend/cypress/e2e/Pages/ComplianceReport/ComplianceReportManagement.feature @@ -6,3 +6,7 @@ Feature: Compliance Report Management And the supplier navigates to the compliance reports page And the supplier creates a new compliance report Then the compliance report introduction is shown + When the supplier navigates to the fuel supply page + And the supplier enters a valid fuel supply row + And saves and returns to the report + Then the compliance report summary includes the quantity diff --git a/frontend/src/views/ComplianceReports/components/ActivityLinkList.jsx b/frontend/src/views/ComplianceReports/components/ActivityLinkList.jsx index 7eba514ff..c968f8e4a 100644 --- a/frontend/src/views/ComplianceReports/components/ActivityLinkList.jsx +++ b/frontend/src/views/ComplianceReports/components/ActivityLinkList.jsx @@ -83,7 +83,11 @@ export const ActivityLinksList = () => { }, [t, navigate, compliancePeriod, complianceReportId]) return ( - + {activityList.map((activity, index) => ( From eadb9b0546d83d95b8c93292b72c24da565a1124 Mon Sep 17 00:00:00 2001 From: Hamed Valiollahi Bayeki Date: Mon, 9 Dec 2024 10:41:32 -0800 Subject: [PATCH 3/3] chore: revert changes --- backend/lcfs/tests/fuel_code/test_fuel_code_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/lcfs/tests/fuel_code/test_fuel_code_service.py b/backend/lcfs/tests/fuel_code/test_fuel_code_service.py index 86b37e76e..c71608031 100644 --- a/backend/lcfs/tests/fuel_code/test_fuel_code_service.py +++ b/backend/lcfs/tests/fuel_code/test_fuel_code_service.py @@ -40,7 +40,7 @@ async def test_get_fuel_codes_success(): ] repo_mock.get_fuel_codes_paginated.return_value = (mock_fuel_codes, 1) - pagination = PaginationRequestSchema(page=1, size=10, filters=[], sort_orders=[]) + pagination = PaginationRequestSchema(page=1, size=10) # Act result = await service.search_fuel_codes(pagination) @@ -49,7 +49,7 @@ async def test_get_fuel_codes_success(): assert isinstance(result.pagination, PaginationResponseSchema) assert len(result.fuel_codes) == 1 assert result.fuel_codes[0].company == "XYZ Corp" - repo_mock.get_fuel_codes_paginated.assert_called_once_with(pagination, []) + repo_mock.get_fuel_codes_paginated.assert_called_once_with(pagination) @pytest.mark.anyio