import { describe, it, expect, vi, beforeEach } from 'vitest' // Mock logger vi.mock('@adonisjs/core/services/logger', () => ({ default: { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() }, })) // Mock DeviceModel vi.mock('../../../app/models/device.js', () => ({ default: { createOrUpdate: vi.fn().mockResolvedValue({}), findByDeviceId: vi.fn().mockResolvedValue(null), findOne: vi.fn().mockResolvedValue(null), updateOne: vi.fn().mockResolvedValue({}), getCollection: vi.fn(), }, })) // Mock ConfigurationModel — dynamically controlled per test vi.mock('#models/configuration', () => ({ default: { find: vi.fn().mockResolvedValue([]), findOne: vi.fn().mockResolvedValue(null), }, })) // Mock FirmwareCatalogService vi.mock('../../../app/services/firmware_catalog_service.js', () => ({ default: class { async resolveUpgradePath() { return [] } }, FirmwareCatalogService: class { async resolveUpgradePath() { return [] } }, })) // Mock schedule_window vi.mock('../../../app/utils/schedule_window.js', () => ({ isWithinSchedule: vi.fn().mockReturnValue(true), })) import ConfigurationEngine from '../../../app/services/configuration_engine.js' import { Device } from '../../../app/domain/device/device.js' import { DeviceId } from '../../../app/domain/device/device_id.js' import { DeviceProperty, DeviceParameter } from '../../../app/domain/device/device_parameter.js' import { ParameterType } from '../../../app/domain/shared/types.js' import ConfigurationModel from '#models/configuration' import DeviceModel from '../../../app/models/device.js' function makeDevice( opts: { manufacturer?: string; productClass?: string; provisioningCode?: string } = {} ): Device { const device = new Device( new DeviceId( opts.manufacturer || 'Sagemcom', 'F8B7FF', opts.productClass || 'Livebox 4', 'LB4-TEST-001' ) ) device.setDataModel('tr-181') if (opts.provisioningCode) { ;(device as any).provisioningCode = opts.provisioningCode } return device } function makeConfig(overrides: any = {}) { return { identifier: 'test-config', name: 'Test Config', version: '1.0.0', priority: 1, policy: 'maintain', enabled: true, criteria: { manufacturer: 'Sagemcom', productClass: 'Livebox 4' }, inventory: [{ path: 'Device.ManagementServer.' }], desiredParameters: [ { name: 'Device.ManagementServer.PeriodicInformInterval', value: '300', type: 'unsignedInt' }, ], firmwareTarget: null, schedule: null, tags: [], ...overrides, } } describe('ConfigurationEngine — coverage', () => { let engine: ConfigurationEngine beforeEach(() => { vi.clearAllMocks() engine = new ConfigurationEngine() }) // --- evaluate() --- it('returns isAlreadyCompliant when no configs exist', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.isAlreadyCompliant).toBe(true) expect(result.configuration).toBeNull() }) it('returns isAlreadyCompliant when no config matches criteria', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { manufacturer: 'Huawei' } }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.isAlreadyCompliant).toBe(true) expect(result.configuration).toBeNull() }) it('selects highest priority config when multiple match', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ identifier: 'low', priority: 1 }), makeConfig({ identifier: 'high', priority: 10 }), makeConfig({ identifier: 'mid', priority: 5 }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration?.identifier).toBe('high') }) it('returns parameterDiffs when device value differs from desired', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([makeConfig()]) const device = makeDevice() // Set a different value device.setParameter( new DeviceParameter( 'Device.ManagementServer.PeriodicInformInterval', '60', ParameterType.UNSIGNED_INT ) ) const result = await engine.evaluate(device) expect(result.parameterDiffs.length).toBe(1) expect(result.parameterDiffs[0].currentValue).toBe('60') expect(result.parameterDiffs[0].targetValue).toBe('300') expect(result.isAlreadyCompliant).toBe(false) }) it('returns empty diffs when device value matches desired', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([makeConfig()]) const device = makeDevice() device.setParameter( new DeviceParameter( 'Device.ManagementServer.PeriodicInformInterval', '300', ParameterType.UNSIGNED_INT ) ) const result = await engine.evaluate(device) expect(result.parameterDiffs.length).toBe(0) expect(result.isAlreadyCompliant).toBe(true) }) it('treats null current value as diff', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([makeConfig()]) const device = makeDevice() // Don't set the parameter — it's unknown const result = await engine.evaluate(device) expect(result.parameterDiffs.length).toBe(1) expect(result.parameterDiffs[0].currentValue).toBeNull() }) // --- matchesCriteria --- it('matchesCriteria matches glob patterns on manufacturer', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { manufacturer: 'Sage*' } }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).not.toBeNull() }) it('matchesCriteria matches wildcard * on productClass', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { manufacturer: 'Sagemcom', productClass: '*' } }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).not.toBeNull() }) it('matchesCriteria rejects when parameterCriteria value mismatches', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { manufacturer: 'Sagemcom', parameterCriteria: [{ name: 'Device.DeviceInfo.ModelName', value: 'WrongModel' }], }, }), ]) const device = makeDevice() device.setParameter( new DeviceParameter('Device.DeviceInfo.ModelName', 'Livebox 4', ParameterType.STRING) ) const result = await engine.evaluate(device) expect(result.configuration).toBeNull() expect(result.isAlreadyCompliant).toBe(true) }) it('matchesCriteria rejects when parameterCriteria param is missing on device', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { manufacturer: 'Sagemcom', parameterCriteria: [{ name: 'Device.DeviceInfo.ModelName', value: 'Livebox 4' }], }, }), ]) const device = makeDevice() // Don't set ModelName → param is missing const result = await engine.evaluate(device) expect(result.configuration).toBeNull() }) // --- shouldApplyOnce (policy: once) --- it('shouldApplyOnce returns true (re-apply) when no provisioningCode on device', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([makeConfig({ policy: 'once' })]) const device = makeDevice() const result = await engine.evaluate(device) // Should evaluate normally (not skip) expect(result.configuration).not.toBeNull() }) it('shouldApplyOnce returns false (skip) when provisioningCode hash matches', async () => { const config = makeConfig({ policy: 'once' }) vi.mocked(ConfigurationModel.find).mockResolvedValue([config]) const device = makeDevice() // Compute the expected provisioning code const { buildProvisioningCode } = await import('../../../app/utils/provisioning_code.js') const expectedPC = buildProvisioningCode(config as any) ;(device as any).provisioningCode = expectedPC const result = await engine.evaluate(device) expect(result.isAlreadyCompliant).toBe(true) expect(result.parameterDiffs.length).toBe(0) }) // --- Numeric and boolean comparison --- it('computeParameterDiffs handles numeric comparison (unsignedInt)', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ desiredParameters: [{ name: 'Device.X.Interval', value: '300', type: 'unsignedInt' }], }), ]) const device = makeDevice() device.setParameter(new DeviceParameter('Device.X.Interval', '300', ParameterType.UNSIGNED_INT)) const result = await engine.evaluate(device) expect(result.parameterDiffs.length).toBe(0) // 300 == 300 }) it('computeParameterDiffs handles boolean comparison', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ desiredParameters: [{ name: 'Device.X.Enabled', value: 'true', type: 'boolean' }], }), ]) const device = makeDevice() device.setParameter(new DeviceParameter('Device.X.Enabled', '1', ParameterType.BOOLEAN)) const result = await engine.evaluate(device) // '1' and 'true' should be treated as same boolean expect(result.parameterDiffs.length).toBe(0) }) it('computeParameterDiffs detects boolean mismatch', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ desiredParameters: [{ name: 'Device.X.Enabled', value: 'true', type: 'boolean' }], }), ]) const device = makeDevice() device.setParameter(new DeviceParameter('Device.X.Enabled', 'false', ParameterType.BOOLEAN)) const result = await engine.evaluate(device) expect(result.parameterDiffs.length).toBe(1) }) // --- matchesCriteria: oui / productClass / serialNumber branches --- it('matchesCriteria rejects when oui does not match', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { oui: 'DEADBEEF' }, }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).toBeNull() }) it('matchesCriteria matches when oui matches exactly', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { oui: 'F8B7FF' }, }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).not.toBeNull() }) it('matchesCriteria rejects when productClass does not match', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { productClass: 'SomethingElse' }, }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).toBeNull() }) it('matchesCriteria rejects when serialNumber does not match', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { serialNumber: 'DIFFERENT-SN' }, }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).toBeNull() }) it('matchesCriteria matches when serialNumber matches exactly', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { serialNumber: 'LB4-TEST-001' }, }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).not.toBeNull() }) it('matchesCriteria returns false for a device without deviceId', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([makeConfig()]) const result = await engine.evaluate({} as any) expect(result.configuration).toBeNull() }) it('matchesCriteria accepts a parameterCriteria match found on plain DeviceRecord (no getParameters)', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ criteria: { manufacturer: 'Sagemcom', parameterCriteria: [{ name: 'Device.DeviceInfo.ModelName', value: 'Livebox 4' }], }, }), ]) // A plain DeviceRecord-like object (no getParameters/getProperties methods) const plainDevice: any = { deviceId: { manufacturer: 'Sagemcom', oui: 'F8B7FF', productClass: 'Livebox 4', serialNumber: 'SN1', }, parameters: [{ name: 'Device.DeviceInfo.ModelName', value: 'Livebox 4' }], properties: [], } const result = await engine.evaluate(plainDevice) expect(result.configuration).not.toBeNull() }) // --- shouldApplyOnce: policy branches --- it('shouldApplyOnce always applies for an unknown/unset policy', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([makeConfig({ policy: 'weird-policy' })]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.configuration).not.toBeNull() }) it('shouldApplyOnce re-applies when provisioningCode has an invalid format', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([makeConfig({ policy: 'once' })]) const device = makeDevice({ provisioningCode: 'not-a-valid-format' }) const result = await engine.evaluate(device) expect(result.isAlreadyCompliant).toBe(false) }) it('shouldApplyOnce re-applies when provisioningCode identifier does not match config', async () => { const config = makeConfig({ policy: 'once', identifier: 'config-a' }) vi.mocked(ConfigurationModel.find).mockResolvedValue([config]) const { buildProvisioningCode } = await import('../../../app/utils/provisioning_code.js') const otherConfig = makeConfig({ policy: 'once', identifier: 'config-b' }) const pcForOtherConfig = buildProvisioningCode(otherConfig as any) const device = makeDevice({ provisioningCode: pcForOtherConfig }) const result = await engine.evaluate(device) expect(result.isAlreadyCompliant).toBe(false) }) it('shouldApplyOnce re-applies when provisioningCode content hash changed', async () => { const config = makeConfig({ policy: 'once' }) vi.mocked(ConfigurationModel.find).mockResolvedValue([config]) // Build a PC for the SAME identifier/version but DIFFERENT content (stale hash) const staleConfig = makeConfig({ policy: 'once', desiredParameters: [{ name: 'Device.Other.Param', value: 'x', type: 'string' }], }) const { buildProvisioningCode } = await import('../../../app/utils/provisioning_code.js') const stalePC = buildProvisioningCode(staleConfig as any) const device = makeDevice({ provisioningCode: stalePC }) const result = await engine.evaluate(device) expect(result.isAlreadyCompliant).toBe(false) }) // --- getDeviceParameterValue: plain DeviceRecord fallback --- it('computeParameterDiffs reads value via plain object fallback (no getParameter method)', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ desiredParameters: [{ name: 'Device.Plain.Param', value: '42', type: 'string' }], }), ]) const plainDevice: any = { deviceId: { manufacturer: 'Sagemcom', oui: 'F8B7FF', productClass: 'Livebox 4', serialNumber: 'LB4-TEST-001', }, parameters: [{ name: 'Device.Plain.Param', value: '42' }], properties: [], } const result = await engine.evaluate(plainDevice) expect(result.parameterDiffs.length).toBe(0) }) it('computeParameterDiffs treats numeric value 0 correctly via plain object fallback', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ desiredParameters: [{ name: 'Device.Plain.Count', value: 0, type: 'string' }], }), ]) const plainDevice: any = { deviceId: { manufacturer: 'Sagemcom', oui: 'F8B7FF', productClass: 'Livebox 4', serialNumber: 'LB4-TEST-001', }, parameters: [{ name: 'Device.Plain.Count', value: 0 }], properties: [], } const result = await engine.evaluate(plainDevice) expect(result.parameterDiffs.length).toBe(0) }) it('computeParameterDiffs treats boolean value via plain object fallback', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ desiredParameters: [{ name: 'Device.Plain.Flag', value: true, type: 'string' }], }), ]) const plainDevice: any = { deviceId: { manufacturer: 'Sagemcom', oui: 'F8B7FF', productClass: 'Livebox 4', serialNumber: 'LB4-TEST-001', }, parameters: [{ name: 'Device.Plain.Flag', value: true }], properties: [], } const result = await engine.evaluate(plainDevice) expect(result.parameterDiffs.length).toBe(0) }) it('getDeviceParameterValue returns null when parameter is not found (Device instance)', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ desiredParameters: [{ name: 'Device.Not.There', value: 'x', type: 'string' }], }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.parameterDiffs[0].currentValue).toBeNull() }) // --- firmwareTarget / schedule window branches --- it('skips firmware migration when outside the schedule window', async () => { const { isWithinSchedule } = await import('../../../app/utils/schedule_window.js') vi.mocked(isWithinSchedule).mockReturnValueOnce(false) vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ firmwareTarget: { productClass: 'Livebox 4', targetVersion: '2.0.0' }, schedule: { start: '00:00', end: '06:00' }, }), ]) const device = makeDevice() const result = await engine.evaluate(device) expect(result.skipFirmware).toBe(true) expect(result.firmwareMigrationPath).toEqual([]) }) it('resolves firmware migration path when current version differs from target', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ firmwareTarget: { productClass: 'Livebox 4', targetVersion: '2.0.0' }, }), ]) const device = makeDevice() // getDeviceParameterValue for Device instances only checks getParameter(), not getProperty() device.setParameter( new DeviceParameter('Device.DeviceInfo.SoftwareVersion', '1.0.0', ParameterType.STRING) ) const firmwareModule = await import('../../../app/services/firmware_catalog_service.js') const FirmwareCatalogService = firmwareModule.default vi.spyOn(FirmwareCatalogService.prototype, 'resolveUpgradePath').mockResolvedValue([ { fromVersion: '1.0.0', toVersion: '2.0.0' } as any, ]) const result = await engine.evaluate(device) expect(result.firmwareMigrationPath.length).toBe(1) expect(result.isAlreadyCompliant).toBe(false) }) it('does not resolve migration path when current version already matches target', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ firmwareTarget: { productClass: 'Livebox 4', targetVersion: '2.0.0' }, }), ]) const device = makeDevice() device.setParameter( new DeviceParameter('Device.DeviceInfo.SoftwareVersion', '2.0.0', ParameterType.STRING) ) const result = await engine.evaluate(device) expect(result.firmwareMigrationPath).toEqual([]) }) it('getDeviceVersion returns null when no version parameter exists', async () => { vi.mocked(ConfigurationModel.find).mockResolvedValue([ makeConfig({ firmwareTarget: { productClass: 'Livebox 4', targetVersion: '2.0.0' }, }), ]) const device = makeDevice() // No SoftwareVersion set anywhere const result = await engine.evaluate(device) expect(result.firmwareMigrationPath).toEqual([]) }) // --- dryRun --- describe('dryRun', () => { it('throws when the configuration is not found', async () => { vi.mocked(ConfigurationModel.findOne).mockResolvedValue(null) await expect(engine.dryRun('missing-config', 'some-device')).rejects.toThrow( 'Configuration missing-config not found' ) }) it('throws when the device is not found', async () => { vi.mocked(ConfigurationModel.findOne).mockResolvedValue(makeConfig() as any) vi.mocked(DeviceModel.findOne).mockResolvedValue(null) await expect(engine.dryRun('test-config', 'missing-device')).rejects.toThrow( 'Device missing-device not found' ) }) it('throws when the configuration does not match the device criteria', async () => { vi.mocked(ConfigurationModel.findOne).mockResolvedValue( makeConfig({ criteria: { manufacturer: 'Huawei' } }) as any ) vi.mocked(DeviceModel.findOne).mockResolvedValue(makeDevice() as any) await expect(engine.dryRun('test-config', 'some-device')).rejects.toThrow( /does not match device/ ) }) it('returns a DryRunResult when configuration matches the device', async () => { vi.mocked(ConfigurationModel.findOne).mockResolvedValue(makeConfig() as any) vi.mocked(DeviceModel.findOne).mockResolvedValue(makeDevice() as any) const result = await engine.dryRun('test-config', 'some-device') expect(result.configurationId).toBe('test-config') expect(result.deviceIdentifier).toBe('some-device') expect(result.evaluation).toBeDefined() expect(result.timestamp).toBeInstanceOf(Date) }) it('dryRun skips (isAlreadyCompliant) when shouldApplyOnce is false (evaluateSpecific)', async () => { const config = makeConfig({ policy: 'once' }) vi.mocked(ConfigurationModel.findOne).mockResolvedValue(config as any) const { buildProvisioningCode } = await import('../../../app/utils/provisioning_code.js') const expectedPC = buildProvisioningCode(config as any) const device = makeDevice({ provisioningCode: expectedPC }) vi.mocked(DeviceModel.findOne).mockResolvedValue(device as any) const result = await engine.dryRun('test-config', 'some-device') expect(result.evaluation.isAlreadyCompliant).toBe(true) expect(result.evaluation.parameterDiffs).toEqual([]) }) it('dryRun skips firmware migration outside schedule window (evaluateSpecific)', async () => { const { isWithinSchedule } = await import('../../../app/utils/schedule_window.js') vi.mocked(isWithinSchedule).mockReturnValueOnce(false) const config = makeConfig({ firmwareTarget: { productClass: 'Livebox 4', targetVersion: '2.0.0' }, schedule: { start: '00:00', end: '06:00' }, }) vi.mocked(ConfigurationModel.findOne).mockResolvedValue(config as any) vi.mocked(DeviceModel.findOne).mockResolvedValue(makeDevice() as any) const result = await engine.dryRun('test-config', 'some-device') expect(result.evaluation.skipFirmware).toBe(true) expect(result.evaluation.firmwareMigrationPath).toEqual([]) }) it('dryRun resolves firmware migration path when version differs (evaluateSpecific)', async () => { const config = makeConfig({ firmwareTarget: { productClass: 'Livebox 4', targetVersion: '2.0.0' }, }) vi.mocked(ConfigurationModel.findOne).mockResolvedValue(config as any) const device = makeDevice() device.setParameter( new DeviceParameter('Device.DeviceInfo.SoftwareVersion', '1.0.0', ParameterType.STRING) ) vi.mocked(DeviceModel.findOne).mockResolvedValue(device as any) const firmwareModule = await import('../../../app/services/firmware_catalog_service.js') const FirmwareCatalogService = firmwareModule.default vi.spyOn(FirmwareCatalogService.prototype, 'resolveUpgradePath').mockResolvedValue([ { fromVersion: '1.0.0', toVersion: '2.0.0' } as any, ]) const result = await engine.dryRun('test-config', 'some-device') expect(result.evaluation.firmwareMigrationPath.length).toBe(1) expect(result.evaluation.isAlreadyCompliant).toBe(false) }) }) // --- complianceReport --- describe('complianceReport', () => { it('throws when the configuration is not found', async () => { vi.mocked(ConfigurationModel.findOne).mockResolvedValue(null) await expect(engine.complianceReport('missing-config')).rejects.toThrow( 'Configuration missing-config not found' ) }) it('returns compliant/non-compliant counts for matching devices', async () => { const config = makeConfig() vi.mocked(ConfigurationModel.findOne).mockResolvedValue(config as any) const compliantDevice = makeDevice() compliantDevice.setParameter( new DeviceParameter( 'Device.ManagementServer.PeriodicInformInterval', '300', ParameterType.UNSIGNED_INT ) ) const nonCompliantDevice = makeDevice() nonCompliantDevice.setParameter( new DeviceParameter( 'Device.ManagementServer.PeriodicInformInterval', '60', ParameterType.UNSIGNED_INT ) ) const nonMatchingDevice = makeDevice({ manufacturer: 'Huawei' }) const mockCollection = { find: vi.fn(() => ({ toArray: vi .fn() .mockResolvedValue([compliantDevice, nonCompliantDevice, nonMatchingDevice]), })), } vi.mocked(DeviceModel.getCollection).mockReturnValue(mockCollection as any) const report = await engine.complianceReport('test-config') expect(report.configurationId).toBe('test-config') expect(report.configurationName).toBe('Test Config') expect(report.totalDevices).toBe(2) // only matching devices expect(report.compliantCount).toBe(1) expect(report.nonCompliantCount).toBe(1) expect(report.devices).toHaveLength(2) }) it('returns zero devices when none match the criteria', async () => { const config = makeConfig({ criteria: { manufacturer: 'NoSuchVendor' } }) vi.mocked(ConfigurationModel.findOne).mockResolvedValue(config as any) const mockCollection = { find: vi.fn(() => ({ toArray: vi.fn().mockResolvedValue([makeDevice()]) })), } vi.mocked(DeviceModel.getCollection).mockReturnValue(mockCollection as any) const report = await engine.complianceReport('test-config') expect(report.totalDevices).toBe(0) expect(report.compliantCount).toBe(0) expect(report.nonCompliantCount).toBe(0) }) }) })