Skip to content

Commit

Permalink
Merge branch 'release-0.2.0' into feat/hamed-save-alt-email
Browse files Browse the repository at this point in the history
  • Loading branch information
hamed-valiollahi authored Dec 10, 2024
2 parents 50ba3d4 + 7c77662 commit f9f2c3e
Show file tree
Hide file tree
Showing 25 changed files with 349 additions and 79 deletions.
4 changes: 2 additions & 2 deletions backend/lcfs/tests/fuel_code/test_fuel_code_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ async def test_approve_fuel_code_not_found():
repo_mock.get_fuel_code.return_value = None

# Act & Assert
with pytest.raises(ServiceException):
with pytest.raises(ValueError, match="Fuel code not found"):
await service.approve_fuel_code(fuel_code_id)
repo_mock.get_fuel_code.assert_called_once_with(fuel_code_id)

Expand All @@ -229,7 +229,7 @@ async def test_approve_fuel_code_invalid_status():
repo_mock.get_fuel_code.return_value = mock_fuel_code

# Act & Assert
with pytest.raises(ServiceException):
with pytest.raises(ValueError, match="Fuel code is not in Draft"):
await service.approve_fuel_code(fuel_code_id)

repo_mock.get_fuel_code.assert_called_once_with(fuel_code_id)
2 changes: 1 addition & 1 deletion backend/lcfs/tests/other_uses/test_other_uses_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ async def test_update_other_use_not_found(other_uses_service):

mock_repo.get_other_use_version_by_user = AsyncMock(return_value=None)

with pytest.raises(ServiceException):
with pytest.raises(ValueError, match="Other use not found"):
await service.update_other_use(other_use_data, UserTypeEnum.SUPPLIER)


Expand Down
22 changes: 8 additions & 14 deletions backend/lcfs/web/api/fuel_code/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,19 +396,8 @@ async def create_fuel_code(self, fuel_code: FuelCode) -> FuelCode:
"""
self.db.add(fuel_code)
await self.db.flush()
await self.db.refresh(
fuel_code,
[
"fuel_code_status",
"fuel_code_prefix",
"fuel_type",
"feedstock_fuel_transport_modes",
"finished_fuel_transport_modes",
],
)
# Manually load nested relationships
await self.db.refresh(fuel_code.fuel_type, ["provision_1", "provision_2"])
return fuel_code
result = await self.get_fuel_code(fuel_code.fuel_code_id)
return result

@repo_handler
async def get_fuel_code(self, fuel_code_id: int) -> FuelCode:
Expand Down Expand Up @@ -593,9 +582,14 @@ async def validate_fuel_code(self, suffix: str, prefix_id: int) -> str:
result = (await self.db.execute(query)).scalar_one_or_none()
if result:
fuel_code_main_version = suffix.split(".")[0]
return await self.get_next_available_sub_version_fuel_code_by_prefix(
suffix = await self.get_next_available_sub_version_fuel_code_by_prefix(
fuel_code_main_version, prefix_id
)
if int(suffix.split(".")[1]) > 9:
return await self.get_next_available_fuel_code_by_prefix(
result.fuel_code_prefix.prefix
)
return suffix
else:
return suffix

Expand Down
4 changes: 4 additions & 0 deletions backend/lcfs/web/api/fuel_code/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ async def convert_to_model(
transport_mode_id=matching_transport_mode.transport_mode_id,
)
)
else:
raise ValueError(f"Invalid transport mode: {transport_mode}")

for transport_mode in fuel_code_schema.finished_fuel_transport_mode or []:
matching_transport_mode = next(
Expand All @@ -221,6 +223,8 @@ async def convert_to_model(
transport_mode_id=matching_transport_mode.transport_mode_id,
)
)
else:
raise ValueError(f"Invalid transport mode: {transport_mode}")

return fuel_code

Expand Down
3 changes: 2 additions & 1 deletion backend/lcfs/web/api/monitoring/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@


@router.get("/health")
def health_check() -> None:
def health_check() -> str:
"""
Checks the health of a project.
It returns 200 if the project is healthy.
"""
return "healthy"
19 changes: 9 additions & 10 deletions backend/lcfs/web/application.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
from importlib import metadata
import structlog
import logging
import uuid

import os
import debugpy
import structlog
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import UJSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import UJSONResponse
from prometheus_fastapi_instrumentator import Instrumentator
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.authentication import (
AuthenticationBackend,
AuthCredentials,
UnauthenticatedUser,
)
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse
import uuid
import contextvars

from lcfs.settings import settings
from lcfs.logging_config import setup_logging, correlation_id_var
from lcfs.web.api.router import api_router
from lcfs.services.keycloak.authentication import UserAuthentication
from lcfs.settings import settings
from lcfs.web.api.router import api_router
from lcfs.web.exception.exception_handler import validation_exception_handler
from lcfs.web.lifetime import register_shutdown_event, register_startup_event

Expand Down Expand Up @@ -67,6 +63,9 @@ async def authenticate(self, request):
if request.scope["method"] == "OPTIONS":
return AuthCredentials([]), UnauthenticatedUser()

if request.url.path == "/api/health": # Skip for health check
return AuthCredentials([]), UnauthenticatedUser()

# Lazily retrieve Redis, session, and settings from app state
redis_client = self.app.state.redis_client
session_factory = self.app.state.db_session_factory
Expand Down
2 changes: 1 addition & 1 deletion backend/lcfs/web/core/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ async def wrapper(*args, **kwargs):
return await func(*args, **kwargs)

# raise the error to the view layer
except (DatabaseException, HTTPException, DataNotFoundException):
except (DatabaseException, HTTPException, DataNotFoundException, ValueError):
raise
# all other errors that occur in the service layer will log an error
except Exception as e:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'

const currentYear = new Date().getFullYear().toString()

Given('the supplier is on the login page', () => {
Given('the user is on the login page', () => {
cy.clearAllCookies()
cy.clearAllLocalStorage()
cy.clearAllSessionStorage()
Expand All @@ -20,7 +20,7 @@ When('the supplier logs in with valid credentials', () => {
cy.getByDataTest('dashboard-container').should('exist')
})

When('the supplier navigates to the compliance reports page', () => {
When('they navigate to the compliance reports page', () => {
cy.get('a[href="/compliance-reporting"]').click()
})

Expand Down Expand Up @@ -140,3 +140,43 @@ Then('the compliance report summary includes the quantity', () => {
.should('be.visible')
.and('have.text', '500')
})

When('the supplier fills out line 6', () => {
cy.get(
'[data-test="renewable-summary"] > .MuiTable-root > .MuiTableBody-root > :nth-child(6) > :nth-child(3)'
)
.find('input')
.type('50{enter}')
.blur()
})

Then('it should round the amount to 25', () => {
cy.get(
'[data-test="renewable-summary"] > .MuiTable-root > .MuiTableBody-root > :nth-child(6) > :nth-child(3)'
)
.find('input')
.should('be.visible')
.and('have.value', '25')
})

When('the supplier accepts the agreement', () => {
cy.get('#signing-authority-declaration').click()
})

When('the supplier submits the report', () => {
cy.contains('button', 'Submit report').click()
cy.get('#modal-btn-submit-report').click()
cy.wait(2000)
})

Then('the status should change to Submitted', () => {
cy.get('[data-test="compliance-report-status"]')
.should('be.visible')
.and('have.text', 'Status: Submitted')
})

Then('they see the previously submitted report', () => {
cy.get('.ag-column-first > a > .MuiBox-root')
.should('be.visible')
.and('have.text', currentYear)
})
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
Feature: Compliance Report Management

Scenario: Supplier saves a draft compliance report
Given the supplier is on the login page
When the supplier logs in with valid credentials
And the supplier navigates to the compliance reports page
Given the user is on the login page
And the supplier logs in with valid credentials
And they navigate 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
When the supplier fills out line 6
Then it should round the amount to 25
When the supplier accepts the agreement
And the supplier submits the report
Then the status should change to Submitted

Scenario: Analyst logs in to review a compliance report
Given the user is on the login page
And the analyst logs in with valid credentials
And they navigate to the compliance reports page
Then they see the previously submitted report
42 changes: 21 additions & 21 deletions frontend/cypress/e2e/Pages/User/UserCreation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,39 @@ When('the IDIR user logs in with valid credentials', () => {
})

When('the IDIR user navigates to the user creation page', () => {
cy.get('a[href="/admin"]').click()
cy.url().should('include', '/admin/users')
cy.contains('New user').click()
cy.url().should('include', '/admin/users/add-user')
cy.get('a[href="/admin"]').click()
cy.url().should('include', '/admin/users')
cy.contains('New user').click()
cy.url().should('include', '/admin/users/add-user')
})

When('the IDIR user fills out the form with valid data', () => {
cy.get('input[id="firstName"]').type('John')
cy.get('input[id="lastName"]').type('Doe')
cy.get('input[id="jobTitle"]').type('Senior Analyst')
cy.get('input[id="userName"]').type('johndoe')
cy.get('input[id="keycloakEmail"]').type('[email protected]')
cy.get('input[id="phone"]').type('1234567890')
cy.get('input[id="mobilePhone"]').type('0987654321')
cy.get('input[id="firstName"]').type('John')
cy.get('input[id="lastName"]').type('Doe')
cy.get('input[id="jobTitle"]').type('Senior Analyst')
cy.get('input[id="userName"]').type('johndoe')
cy.get('input[id="keycloakEmail"]').type('[email protected]')
cy.get('input[id="phone"]').type('1234567890')
cy.get('input[id="mobilePhone"]').type('0987654321')

// Select the Analyst role
cy.get('input[type="radio"][value="analyst"]').check()
// Select the Analyst role
cy.get('input[type="radio"][value="analyst"]').check()
})

When('the IDIR user submits the form', () => {
cy.get('button[data-test="saveUser"]').click()
cy.get('button[data-test="saveUser"]').click()
})

Then('a success message is displayed', () => {
cy.get("[data-test='alert-box'] .MuiBox-root").should(
'contain',
'User has been successfully saved.'
)
cy.get("[data-test='alert-box'] .MuiBox-root").should(
'contain',
'User has been successfully saved.'
)
})

Then('the new user appears in the user list', () => {
cy.visit('/admin/users')
cy.contains('a', Cypress.env('[email protected]')).should('be.visible')
cy.visit('/admin/users')
cy.contains('a', Cypress.env('[email protected]')).should('be.visible')
})

// Test for validation error
Expand All @@ -75,7 +75,7 @@ When('the IDIR user fills out the form with invalid data', () => {
})

Then('an error message is displayed for validation', () => {
cy.get('#userName-helper-text').should('contain', 'User name is required')
cy.get('#userName-helper-text').should('contain', 'User name is required')
})

// Cleanup after the test
Expand Down
2 changes: 1 addition & 1 deletion frontend/cypress/e2e/accessibility.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('Accessibility Tests for LCFS', () => {
it('Should have no accessibility violations in the navigation bar', () => {
cy.visit('/')
cy.injectAxe()
cy.login(
cy.loginWith(
'idir',
Cypress.env('IDIR_TEST_USER'),
Cypress.env('IDIR_TEST_PASS')
Expand Down
2 changes: 1 addition & 1 deletion frontend/cypress/e2e/add__edit_org.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

describe('Add Organization Test Suite', () => {
beforeEach(() => {
cy.login(
cy.loginWith(
'idir',
Cypress.env('IDIR_TEST_USER'),
Cypress.env('IDIR_TEST_PASS')
Expand Down
4 changes: 2 additions & 2 deletions frontend/cypress/e2e/disclaimer_banner.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
describe('Disclaimer Banner Visibility Test Suite', () => {
context('BCeID User', () => {
beforeEach(() => {
cy.login(
cy.loginWith(
'bceid',
Cypress.env('BCEID_TEST_USER'),
Cypress.env('BCEID_TEST_PASS')
Expand All @@ -29,7 +29,7 @@ describe('Disclaimer Banner Visibility Test Suite', () => {

context('IDIR User', () => {
beforeEach(() => {
cy.login(
cy.loginWith(
'idir',
Cypress.env('IDIR_TEST_USER'),
Cypress.env('IDIR_TEST_PASS')
Expand Down
2 changes: 1 addition & 1 deletion frontend/cypress/e2e/organization.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
describe('Organization Test Suite', () => {
beforeEach(() => {
// Login and visit the page
cy.login(
cy.loginWith(
'idir',
Cypress.env('IDIR_TEST_USER'),
Cypress.env('IDIR_TEST_PASS')
Expand Down
10 changes: 5 additions & 5 deletions frontend/cypress/e2e/user_flow.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ describe('User Login Test Suite', () => {

describe('IDIR Login Flow', () => {
it('fails login with wrong IDIR user credentials', () => {
cy.login('idir', 'wrong_username', 'wrong_password')
cy.loginWith('idir', 'wrong_username', 'wrong_password')
cy.getByDataTest('main-layout-navbar').should('not.exist')
})

it('completes login with IDIR user credentials', () => {
cy.login(
cy.loginWith(
'idir',
Cypress.env('IDIR_TEST_USER'),
Cypress.env('IDIR_TEST_PASS')
Expand All @@ -42,7 +42,7 @@ describe('User Login Test Suite', () => {
})

it('executes logout functionality for IDIR user', () => {
cy.login(
cy.loginWith(
'idir',
Cypress.env('IDIR_TEST_USER'),
Cypress.env('IDIR_TEST_PASS')
Expand All @@ -53,12 +53,12 @@ describe('User Login Test Suite', () => {

describe('BCeID Login Flow', () => {
it('fails login with wrong BCeID user credentials', () => {
cy.login('bceid', 'wrong_username', 'wrong_password')
cy.loginWith('bceid', 'wrong_username', 'wrong_password')
cy.getByDataTest('main-layout-navbar').should('not.exist')
})

it('completes login with BCeID user credentials', () => {
cy.login(
cy.loginWith(
'bceid',
Cypress.env('BCEID_TEST_USER'),
Cypress.env('BCEID_TEST_PASS')
Expand Down
Loading

0 comments on commit f9f2c3e

Please sign in to comment.