Tests/Admin-UserLookup.Tests.ps1

BeforeAll {
    $ModulePath = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
    $ModuleName = 'Admin-UserLookup'
    $ManifestPath = Join-Path $ModulePath "$ModuleName\$ModuleName.psd1"

    # Remove module if already loaded, then import fresh
    if (Get-Module -Name $ModuleName -ErrorAction SilentlyContinue) {
        Remove-Module -Name $ModuleName -Force
    }
    Import-Module $ManifestPath -Force -ErrorAction Stop
}

AfterAll {
    if (Get-Module -Name 'Admin-UserLookup') {
        Remove-Module -Name 'Admin-UserLookup' -Force
    }
}

Describe 'Module: Admin-UserLookup' {

    Context 'Module Loading' {
        It 'Should import without errors' {
            { Import-Module $ManifestPath -Force } | Should -Not -Throw
        }

        It 'Should be loaded in the current session' {
            Get-Module -Name 'Admin-UserLookup' | Should -Not -BeNullOrEmpty
        }

        It 'Should export exactly 5 public functions' {
            $exportedFunctions = (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys
            $exportedFunctions.Count | Should -Be 5
        }

        It 'Should export Get-UserEverything' {
            (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys | Should -Contain 'Get-UserEverything'
        }

        It 'Should export Get-UserADDetails' {
            (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys | Should -Contain 'Get-UserADDetails'
        }

        It 'Should export Get-UserM365Details' {
            (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys | Should -Contain 'Get-UserM365Details'
        }

        It 'Should export Get-UserDevices' {
            (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys | Should -Contain 'Get-UserDevices'
        }

        It 'Should export Get-UserSignInHistory' {
            (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys | Should -Contain 'Get-UserSignInHistory'
        }

        It 'Should NOT export Resolve-UserIdentity (private)' {
            (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys | Should -Not -Contain 'Resolve-UserIdentity'
        }

        It 'Should NOT export New-HtmlDashboard (private)' {
            (Get-Module -Name 'Admin-UserLookup').ExportedFunctions.Keys | Should -Not -Contain 'New-HtmlDashboard'
        }
    }

    Context 'Module Manifest' {
        BeforeAll {
            $manifest = Test-ModuleManifest -Path $ManifestPath -ErrorAction Stop
        }

        It 'Should have the correct GUID' {
            $manifest.GUID.ToString() | Should -Be 'e5f6a7b8-2c13-4e9f-d0a1-6c7d8e9f0a12'
        }

        It 'Should require PowerShell 5.1 or later' {
            $manifest.PowerShellVersion | Should -Be '5.1'
        }

        It 'Should have Larry Roberts as author' {
            $manifest.Author | Should -BeLike '*Larry Roberts*'
        }

        It 'Should have a description' {
            $manifest.Description | Should -Not -BeNullOrEmpty
        }

        It 'Should include expected tags' {
            $tags = $manifest.PrivateData.PSData.Tags
            $tags | Should -Contain 'User'
            $tags | Should -Contain 'Lookup'
            $tags | Should -Contain 'ActiveDirectory'
            $tags | Should -Contain 'M365'
            $tags | Should -Contain 'Intune'
            $tags | Should -Contain 'Identity'
            $tags | Should -Contain 'Admin'
            $tags | Should -Contain 'MFA'
        }

        It 'Should have a ProjectUri' {
            $manifest.PrivateData.PSData.ProjectUri | Should -Be 'https://github.com/larro1991/Admin-UserLookup'
        }

        It 'Should have a LicenseUri' {
            $manifest.PrivateData.PSData.LicenseUri | Should -Be 'https://github.com/larro1991/Admin-UserLookup/blob/master/LICENSE'
        }

        It 'Should have version 1.0.0' {
            $manifest.Version.ToString() | Should -Be '1.0.0'
        }
    }

    Context 'Get-UserEverything Parameters' {
        BeforeAll {
            $command = Get-Command -Name 'Get-UserEverything' -Module 'Admin-UserLookup'
        }

        It 'Should have a mandatory Identity parameter' {
            $param = $command.Parameters['Identity']
            $param | Should -Not -BeNullOrEmpty
            $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] -and $_.Mandatory } | Should -Not -BeNullOrEmpty
        }

        It 'Should have an optional OutputPath parameter' {
            $param = $command.Parameters['OutputPath']
            $param | Should -Not -BeNullOrEmpty
            $param.ParameterType.Name | Should -Be 'String'
        }

        It 'Should have an IncludeSignInHistory switch parameter' {
            $param = $command.Parameters['IncludeSignInHistory']
            $param | Should -Not -BeNullOrEmpty
            $param.ParameterType.Name | Should -Be 'SwitchParameter'
        }
    }

    Context 'Get-UserADDetails Parameters' {
        BeforeAll {
            $command = Get-Command -Name 'Get-UserADDetails' -Module 'Admin-UserLookup'
        }

        It 'Should have a mandatory Identity parameter' {
            $param = $command.Parameters['Identity']
            $param | Should -Not -BeNullOrEmpty
            $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] -and $_.Mandatory } | Should -Not -BeNullOrEmpty
        }

        It 'Should accept pipeline input' {
            $param = $command.Parameters['Identity']
            $pipelineAttr = $param.Attributes | Where-Object {
                $_ -is [System.Management.Automation.ParameterAttribute] -and $_.ValueFromPipeline
            }
            $pipelineAttr | Should -Not -BeNullOrEmpty
        }
    }

    Context 'Get-UserM365Details Parameters' {
        BeforeAll {
            $command = Get-Command -Name 'Get-UserM365Details' -Module 'Admin-UserLookup'
        }

        It 'Should have a mandatory Identity parameter' {
            $param = $command.Parameters['Identity']
            $param | Should -Not -BeNullOrEmpty
            $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] -and $_.Mandatory } | Should -Not -BeNullOrEmpty
        }
    }

    Context 'Get-UserDevices Parameters' {
        BeforeAll {
            $command = Get-Command -Name 'Get-UserDevices' -Module 'Admin-UserLookup'
        }

        It 'Should have a mandatory Identity parameter' {
            $param = $command.Parameters['Identity']
            $param | Should -Not -BeNullOrEmpty
            $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] -and $_.Mandatory } | Should -Not -BeNullOrEmpty
        }
    }

    Context 'Get-UserSignInHistory Parameters' {
        BeforeAll {
            $command = Get-Command -Name 'Get-UserSignInHistory' -Module 'Admin-UserLookup'
        }

        It 'Should have a mandatory Identity parameter' {
            $param = $command.Parameters['Identity']
            $param | Should -Not -BeNullOrEmpty
            $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] -and $_.Mandatory } | Should -Not -BeNullOrEmpty
        }

        It 'Should have a DaysBack parameter with default of 7' {
            $param = $command.Parameters['DaysBack']
            $param | Should -Not -BeNullOrEmpty
            $param.ParameterType.Name | Should -Be 'Int32'
        }

        It 'Should validate DaysBack range is 1 to 90' {
            $param = $command.Parameters['DaysBack']
            $rangeAttr = $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ValidateRangeAttribute] }
            $rangeAttr | Should -Not -BeNullOrEmpty
            $rangeAttr.MinRange | Should -Be 1
            $rangeAttr.MaxRange | Should -Be 90
        }
    }

    Context 'Get-UserEverything (Mocked)' {
        BeforeAll {
            # Mock Resolve-UserIdentity
            Mock -CommandName 'Resolve-UserIdentity' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    SAMAccountName = 'jsmith'
                    UPN            = 'john.smith@contoso.com'
                    Mail           = 'john.smith@contoso.com'
                    ObjectId       = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
                    DisplayName    = 'John Smith'
                    Enabled        = $true
                }
            }

            # Mock Get-UserADDetails
            Mock -CommandName 'Get-UserADDetails' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    SAMAccountName       = 'jsmith'
                    UPN                  = 'john.smith@contoso.com'
                    DisplayName          = 'John Smith'
                    Email                = 'john.smith@contoso.com'
                    Title                = 'Financial Analyst'
                    Department           = 'Finance'
                    Manager              = 'Jane Doe'
                    Office               = 'Building A, Floor 3'
                    DistinguishedName    = 'CN=John Smith,OU=Finance,DC=contoso,DC=com'
                    Enabled              = $true
                    LockedOut            = $false
                    PasswordLastSet      = (Get-Date).AddDays(-30)
                    PasswordExpired      = $false
                    PasswordNeverExpires = $false
                    LastLogonDate        = (Get-Date).AddHours(-2)
                    Created              = (Get-Date).AddYears(-3)
                    MemberOf             = @('Finance Team', 'VPN Users', 'All Staff')
                    DirectReports        = @('Bob Wilson')
                    AccountExpirationDate = $null
                    Description          = 'Finance department analyst'
                }
            }

            # Mock Get-UserM365Details
            Mock -CommandName 'Get-UserM365Details' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    LicenseAssignments       = @('Microsoft 365 E5')
                    MailboxSize              = '4.82 GB'
                    MailboxItemCount         = 12543
                    OneDriveUsage            = '18.7 GB'
                    TeamsActivity            = '2026-02-15'
                    SharePointSites          = 5
                    SharedMailboxAccess      = @('finance@contoso.com')
                    MFAStatus                = 'Enabled'
                    MFAMethods               = @('Microsoft Authenticator', 'Phone (SMS/Call)')
                    ConditionalAccessPolicies = @('Require MFA for All Users', 'Block Legacy Auth')
                }
            }

            # Mock Get-UserDevices
            Mock -CommandName 'Get-UserDevices' -ModuleName 'Admin-UserLookup' -MockWith {
                @(
                    [PSCustomObject]@{
                        DeviceName      = 'DESKTOP-JS001'
                        OS              = 'Windows'
                        OSVersion       = '10.0.22631'
                        ComplianceState = 'Compliant'
                        LastCheckIn     = (Get-Date).AddHours(-1)
                        Manufacturer    = 'Dell Inc.'
                        Model           = 'Latitude 5540'
                        SerialNumber    = 'ABC123DEF'
                        EnrollmentDate  = (Get-Date).AddMonths(-6)
                        IsManaged       = $true
                        EncryptionStatus = 'Encrypted'
                    }
                )
            }

            # Mock Get-UserSignInHistory
            Mock -CommandName 'Get-UserSignInHistory' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    RecentSignIns        = @(
                        [PSCustomObject]@{
                            Date      = (Get-Date).AddHours(-1)
                            App       = 'Microsoft Teams'
                            IPAddress = '198.51.100.42'
                            Location  = 'New York, NY, US'
                            Status    = 'Success'
                            MFAResult = 'Satisfied'
                        }
                    )
                    FailedAttempts       = [PSCustomObject]@{ Count = 0; Details = @() }
                    RiskDetections       = @()
                    LastSuccessfulSignIn = (Get-Date).AddHours(-1)
                    LastFailedSignIn     = $null
                    UnusualLocations     = @()
                }
            }
        }

        It 'Should return a consolidated result object' {
            $result = Get-UserEverything -Identity 'jsmith'
            $result | Should -Not -BeNullOrEmpty
        }

        It 'Should include ADAccount section' {
            $result = Get-UserEverything -Identity 'jsmith'
            $result.ADAccount | Should -Not -BeNullOrEmpty
            $result.ADAccount.DisplayName | Should -Be 'John Smith'
        }

        It 'Should include M365 section' {
            $result = Get-UserEverything -Identity 'jsmith'
            $result.M365 | Should -Not -BeNullOrEmpty
            $result.M365.MFAStatus | Should -Be 'Enabled'
        }

        It 'Should include Devices section' {
            $result = Get-UserEverything -Identity 'jsmith'
            $result.Devices | Should -Not -BeNullOrEmpty
            $result.Devices.Count | Should -Be 1
        }

        It 'Should NOT include SignIns by default' {
            $result = Get-UserEverything -Identity 'jsmith'
            Should -Invoke -CommandName 'Get-UserSignInHistory' -ModuleName 'Admin-UserLookup' -Times 0 -Exactly
        }

        It 'Should include SignIns when -IncludeSignInHistory is specified' {
            $result = Get-UserEverything -Identity 'jsmith' -IncludeSignInHistory
            $result.SignIns | Should -Not -BeNullOrEmpty
            Should -Invoke -CommandName 'Get-UserSignInHistory' -ModuleName 'Admin-UserLookup' -Times 1
        }

        It 'Should include Metadata with timing info' {
            $result = Get-UserEverything -Identity 'jsmith'
            $result.Metadata | Should -Not -BeNullOrEmpty
            $result.Metadata.ElapsedSeconds | Should -BeOfType [double]
            $result.Metadata.QueryTimestamp | Should -BeOfType [datetime]
        }

        It 'Should track loaded sections in metadata' {
            $result = Get-UserEverything -Identity 'jsmith'
            $result.Metadata.SectionsLoaded | Should -Contain 'ADAccount'
            $result.Metadata.SectionsLoaded | Should -Contain 'M365'
            $result.Metadata.SectionsLoaded | Should -Contain 'Devices'
        }

        It 'Should call Resolve-UserIdentity with provided identity' {
            Get-UserEverything -Identity 'jsmith'
            Should -Invoke -CommandName 'Resolve-UserIdentity' -ModuleName 'Admin-UserLookup' -ParameterFilter { $Identity -eq 'jsmith' }
        }
    }

    Context 'Get-UserADDetails (Mocked)' {
        BeforeAll {
            Mock -CommandName 'Resolve-UserIdentity' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    SAMAccountName = 'jsmith'
                    UPN            = 'john.smith@contoso.com'
                    Mail           = 'john.smith@contoso.com'
                    ObjectId       = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
                    DisplayName    = 'John Smith'
                    Enabled        = $true
                }
            }

            Mock -CommandName 'Get-ADUser' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    SamAccountName              = 'jsmith'
                    UserPrincipalName           = 'john.smith@contoso.com'
                    DisplayName                 = 'John Smith'
                    Mail                        = 'john.smith@contoso.com'
                    Title                       = 'Financial Analyst'
                    Department                  = 'Finance'
                    Manager                     = 'CN=Jane Doe,OU=Management,DC=contoso,DC=com'
                    physicalDeliveryOfficeName   = 'Building A'
                    DistinguishedName           = 'CN=John Smith,OU=Finance,DC=contoso,DC=com'
                    Enabled                     = $true
                    LockedOut                   = $false
                    PasswordLastSet             = (Get-Date).AddDays(-30)
                    PasswordExpired             = $false
                    PasswordNeverExpires        = $false
                    LastLogonDate               = (Get-Date).AddHours(-2)
                    WhenCreated                 = (Get-Date).AddYears(-3)
                    MemberOf                    = @('CN=Finance Team,OU=Groups,DC=contoso,DC=com')
                    DirectReports               = @('CN=Bob Wilson,OU=Finance,DC=contoso,DC=com')
                    AccountExpirationDate       = $null
                    Description                 = 'Finance analyst'
                }
            }

            Mock -CommandName 'Get-ADGroup' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ Name = 'Finance Team' }
            }
        }

        It 'Should return AD details with expected properties' {
            $result = Get-UserADDetails -Identity 'jsmith'
            $result.SAMAccountName | Should -Be 'jsmith'
            $result.DisplayName | Should -Be 'John Smith'
            $result.Department | Should -Be 'Finance'
            $result.Enabled | Should -Be $true
        }

        It 'Should resolve group memberships to names' {
            $result = Get-UserADDetails -Identity 'jsmith'
            $result.MemberOf | Should -Not -BeNullOrEmpty
        }

        It 'Should include password status properties' {
            $result = Get-UserADDetails -Identity 'jsmith'
            $result.PasswordLastSet | Should -Not -BeNullOrEmpty
            $result.PasswordExpired | Should -Be $false
            $result.PasswordNeverExpires | Should -Be $false
        }
    }

    Context 'Get-UserM365Details (Mocked)' {
        BeforeAll {
            Mock -CommandName 'Get-MgContext' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ Account = 'admin@contoso.com'; TenantId = 'tenant-id' }
            }

            Mock -CommandName 'Get-MgUser' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    Id                = 'user-guid-here'
                    DisplayName       = 'John Smith'
                    UserPrincipalName = 'john.smith@contoso.com'
                    AssignedLicenses  = @([PSCustomObject]@{ SkuId = 'sku-guid-e5' })
                    AccountEnabled    = $true
                }
            }

            Mock -CommandName 'Get-MgSubscribedSku' -ModuleName 'Admin-UserLookup' -MockWith {
                @([PSCustomObject]@{ SkuId = 'sku-guid-e5'; SkuPartNumber = 'SPE_E5' })
            }

            Mock -CommandName 'Get-MgUserMailFolder' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ TotalItemCount = 5000 }
            }

            Mock -CommandName 'Get-MgUserDrive' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ Quota = [PSCustomObject]@{ Used = 20GB } }
            }

            Mock -CommandName 'Get-MgUserMemberOf' -ModuleName 'Admin-UserLookup' -MockWith { @() }

            Mock -CommandName 'Get-MgUserAuthenticationMethod' -ModuleName 'Admin-UserLookup' -MockWith {
                @(
                    [PSCustomObject]@{ AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.microsoftAuthenticatorAuthenticationMethod' } },
                    [PSCustomObject]@{ AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.passwordAuthenticationMethod' } }
                )
            }

            Mock -CommandName 'Invoke-MgGraphRequest' -ModuleName 'Admin-UserLookup' -MockWith { @{ value = @() } }
        }

        It 'Should return M365 details with licenses' {
            $result = Get-UserM365Details -Identity 'john.smith@contoso.com'
            $result.LicenseAssignments | Should -Not -BeNullOrEmpty
            $result.LicenseAssignments | Should -Contain 'Microsoft 365 E5'
        }

        It 'Should detect MFA as enabled when Authenticator is registered' {
            $result = Get-UserM365Details -Identity 'john.smith@contoso.com'
            $result.MFAStatus | Should -Be 'Enabled'
        }

        It 'Should include OneDrive usage' {
            $result = Get-UserM365Details -Identity 'john.smith@contoso.com'
            $result.OneDriveUsage | Should -Not -Be 'N/A'
        }

        It 'Should include mailbox item count' {
            $result = Get-UserM365Details -Identity 'john.smith@contoso.com'
            $result.MailboxItemCount | Should -Be 5000
        }
    }

    Context 'Get-UserDevices (Mocked)' {
        BeforeAll {
            Mock -CommandName 'Get-MgContext' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ Account = 'admin@contoso.com' }
            }

            Mock -CommandName 'Get-MgUser' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ Id = 'user-guid-here' }
            }

            Mock -CommandName 'Get-MgUserManagedDevice' -ModuleName 'Admin-UserLookup' -MockWith {
                @(
                    [PSCustomObject]@{
                        DeviceName        = 'LAPTOP-001'
                        OperatingSystem   = 'Windows'
                        OsVersion         = '10.0.22631'
                        ComplianceState   = 'compliant'
                        LastSyncDateTime  = (Get-Date).AddHours(-3)
                        Manufacturer      = 'Lenovo'
                        Model             = 'ThinkPad X1 Carbon'
                        SerialNumber      = 'SN12345'
                        EnrolledDateTime  = (Get-Date).AddMonths(-12)
                        IsManaged         = $true
                        IsEncrypted       = $true
                    },
                    [PSCustomObject]@{
                        DeviceName        = 'iPhone-JSmith'
                        OperatingSystem   = 'iOS'
                        OsVersion         = '17.3'
                        ComplianceState   = 'compliant'
                        LastSyncDateTime  = (Get-Date).AddDays(-1)
                        Manufacturer      = 'Apple'
                        Model             = 'iPhone 15 Pro'
                        SerialNumber      = 'SN67890'
                        EnrolledDateTime  = (Get-Date).AddMonths(-3)
                        IsManaged         = $true
                        IsEncrypted       = $true
                    }
                )
            }

            Mock -CommandName 'Get-MgUserRegisteredDevice' -ModuleName 'Admin-UserLookup' -MockWith { @() }
        }

        It 'Should return array of device objects' {
            $result = Get-UserDevices -Identity 'john.smith@contoso.com'
            $result.Count | Should -Be 2
        }

        It 'Should include device name and OS' {
            $result = Get-UserDevices -Identity 'john.smith@contoso.com'
            $result[0].DeviceName | Should -Be 'LAPTOP-001'
            $result[0].OS | Should -Be 'Windows'
        }

        It 'Should normalize compliance state' {
            $result = Get-UserDevices -Identity 'john.smith@contoso.com'
            $result[0].ComplianceState | Should -Be 'Compliant'
        }

        It 'Should include encryption status' {
            $result = Get-UserDevices -Identity 'john.smith@contoso.com'
            $result[0].EncryptionStatus | Should -Be 'Encrypted'
        }
    }

    Context 'Get-UserSignInHistory (Mocked)' {
        BeforeAll {
            Mock -CommandName 'Get-MgContext' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ Account = 'admin@contoso.com' }
            }

            Mock -CommandName 'Get-MgUser' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{ Id = 'user-guid-here'; UserPrincipalName = 'john.smith@contoso.com' }
            }

            Mock -CommandName 'Invoke-MgGraphRequest' -ModuleName 'Admin-UserLookup' -MockWith {
                param($Method, $Uri)
                if ($Uri -match 'signIns') {
                    @{
                        value = @(
                            @{
                                createdDateTime            = (Get-Date).AddHours(-2).ToUniversalTime().ToString('o')
                                appDisplayName             = 'Microsoft Teams'
                                ipAddress                  = '198.51.100.42'
                                status                     = @{ errorCode = 0; failureReason = $null }
                                location                   = @{ city = 'New York'; state = 'NY'; countryOrRegion = 'US' }
                                mfaDetail                  = @{ authDetail = 'MFA completed' }
                                authenticationRequirement  = 'multiFactorAuthentication'
                            },
                            @{
                                createdDateTime            = (Get-Date).AddHours(-5).ToUniversalTime().ToString('o')
                                appDisplayName             = 'Outlook'
                                ipAddress                  = '203.0.113.99'
                                status                     = @{ errorCode = 50126; failureReason = 'Invalid password' }
                                location                   = @{ city = 'Moscow'; state = $null; countryOrRegion = 'RU' }
                                mfaDetail                  = $null
                                authenticationRequirement  = 'singleFactorAuthentication'
                            }
                        )
                    }
                }
                elseif ($Uri -match 'riskDetections') {
                    @{ value = @() }
                }
                else {
                    @{ value = @() }
                }
            }
        }

        It 'Should return sign-in history object' {
            $result = Get-UserSignInHistory -Identity 'john.smith@contoso.com'
            $result | Should -Not -BeNullOrEmpty
        }

        It 'Should include recent sign-ins' {
            $result = Get-UserSignInHistory -Identity 'john.smith@contoso.com'
            $result.RecentSignIns.Count | Should -BeGreaterThan 0
        }

        It 'Should track failed attempts' {
            $result = Get-UserSignInHistory -Identity 'john.smith@contoso.com'
            $result.FailedAttempts.Count | Should -BeGreaterThan 0
        }

        It 'Should record last successful sign-in' {
            $result = Get-UserSignInHistory -Identity 'john.smith@contoso.com'
            $result.LastSuccessfulSignIn | Should -Not -BeNullOrEmpty
        }

        It 'Should record last failed sign-in' {
            $result = Get-UserSignInHistory -Identity 'john.smith@contoso.com'
            $result.LastFailedSignIn | Should -Not -BeNullOrEmpty
        }

        It 'Should accept DaysBack parameter' {
            { Get-UserSignInHistory -Identity 'john.smith@contoso.com' -DaysBack 30 } | Should -Not -Throw
        }
    }

    Context 'HTML Dashboard (Mocked)' {
        BeforeAll {
            Mock -CommandName 'Resolve-UserIdentity' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    SAMAccountName = 'jsmith'
                    UPN            = 'john.smith@contoso.com'
                    Mail           = 'john.smith@contoso.com'
                    ObjectId       = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
                    DisplayName    = 'John Smith'
                    Enabled        = $true
                }
            }

            Mock -CommandName 'Get-UserADDetails' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    SAMAccountName = 'jsmith'; UPN = 'john.smith@contoso.com'
                    DisplayName = 'John Smith'; Email = 'john.smith@contoso.com'
                    Title = 'Analyst'; Department = 'Finance'; Manager = 'Jane Doe'
                    Office = 'HQ'; DistinguishedName = 'CN=John Smith,DC=contoso,DC=com'
                    Enabled = $true; LockedOut = $false
                    PasswordLastSet = (Get-Date).AddDays(-10); PasswordExpired = $false
                    PasswordNeverExpires = $false; LastLogonDate = (Get-Date).AddHours(-1)
                    Created = (Get-Date).AddYears(-2); MemberOf = @('Finance Team')
                    DirectReports = @(); AccountExpirationDate = $null; Description = ''
                }
            }

            Mock -CommandName 'Get-UserM365Details' -ModuleName 'Admin-UserLookup' -MockWith {
                [PSCustomObject]@{
                    LicenseAssignments = @('Microsoft 365 E5'); MailboxSize = '2.5 GB'
                    MailboxItemCount = 3000; OneDriveUsage = '10 GB'; TeamsActivity = '2026-02-15'
                    SharePointSites = 3; SharedMailboxAccess = @(); MFAStatus = 'Enabled'
                    MFAMethods = @('Microsoft Authenticator'); ConditionalAccessPolicies = @('Require MFA')
                }
            }

            Mock -CommandName 'Get-UserDevices' -ModuleName 'Admin-UserLookup' -MockWith { @() }
        }

        It 'Should generate an HTML file when OutputPath is specified' {
            $testPath = Join-Path $env:TEMP "Admin-UserLookup-Test-$(Get-Random).html"
            try {
                Get-UserEverything -Identity 'jsmith' -OutputPath $testPath
                Test-Path $testPath | Should -Be $true
            }
            finally {
                if (Test-Path $testPath) { Remove-Item $testPath -Force }
            }
        }

        It 'Should include accent color in generated HTML' {
            $testPath = Join-Path $env:TEMP "Admin-UserLookup-Test-$(Get-Random).html"
            try {
                Get-UserEverything -Identity 'jsmith' -OutputPath $testPath
                $content = Get-Content $testPath -Raw
                $content | Should -Match '#f0883e'
            }
            finally {
                if (Test-Path $testPath) { Remove-Item $testPath -Force }
            }
        }
    }
}