set('graph_contracts.types.deviceConfiguration', [ 'resource' => 'deviceManagement/deviceConfigurations', 'allowed_select' => ['id', 'displayName'], 'allowed_expand' => ['assignments'], 'type_family' => [ '#microsoft.graph.deviceConfiguration', '#microsoft.graph.windows10CustomConfiguration', ], ]); config()->set('graph_contracts.types.settingsCatalogPolicy', [ 'resource' => 'deviceManagement/configurationPolicies', 'allowed_select' => ['id'], 'allowed_expand' => [], 'type_family' => ['#microsoft.graph.deviceManagementConfigurationPolicy'], 'update_whitelist' => ['name', 'description'], 'update_map' => ['displayName' => 'name'], 'update_strip_keys' => ['platforms', 'technologies', 'templateReference', 'assignments'], 'settings_write' => [ 'path_template' => 'deviceManagement/configurationPolicies/{id}/settings/{settingId}', 'method' => 'PATCH', ], ]); $this->registry = app(GraphContractRegistry::class); }); it('sanitizes disallowed select and expand values', function () { $result = $this->registry->sanitizeQuery('deviceConfiguration', [ '$select' => ['id', 'displayName', 'unsupported'], '$expand' => ['assignments', 'badExpand'], ]); $query = $result['query']; $warnings = $result['warnings']; expect($query['$select'])->toBe(['id', 'displayName']); expect($query['$expand'])->toBe(['assignments']); expect($warnings)->not->toBeEmpty(); }); it('matches derived types within family', function () { expect($this->registry->matchesTypeFamily('deviceConfiguration', '#microsoft.graph.windows10CustomConfiguration'))->toBeTrue(); expect($this->registry->matchesTypeFamily('deviceConfiguration', '#microsoft.graph.androidCompliancePolicy'))->toBeFalse(); }); it('detects capability errors for downgrade', function () { $response = new GraphResponse( success: false, data: [], status: 400, errors: [['message' => 'Request is invalid due to $select']] ); $shouldDowngrade = $this->registry->shouldDowngradeOnCapabilityError($response, ['$select' => ['displayName']]); expect($shouldDowngrade)->toBeTrue(); }); it('provides contract for settings catalog policies', function () { $contract = config('graph_contracts.types.settingsCatalogPolicy'); expect($contract)->not->toBeEmpty(); expect($contract['resource'])->toBe('deviceManagement/configurationPolicies'); expect($this->registry->matchesTypeFamily('settingsCatalogPolicy', '#microsoft.graph.deviceManagementConfigurationPolicy'))->toBeTrue(); }); it('sanitizes update payloads for settings catalog policies', function () { $payload = [ 'id' => 'scp-1', '@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy', 'displayName' => 'Config', 'Description' => 'desc', 'version' => 5, 'createdDateTime' => '2024-01-01T00:00:00Z', 'settings' => [ [ 'id' => 'setting-1', 'settingInstance' => [ '@odata.type' => '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance', 'settingDefinitionId' => 'setting_definition', 'simpleSettingValue' => ['value' => 'bar'], ], ], ], 'Platforms' => ['windows'], 'unknown' => 'drop-me', ]; $sanitized = $this->registry->sanitizeUpdatePayload('settingsCatalogPolicy', $payload); expect($sanitized)->toHaveKeys(['name', 'description']); expect($sanitized)->not->toHaveKey('id'); expect($sanitized)->not->toHaveKey('@odata.type'); expect($sanitized)->not->toHaveKey('version'); expect($sanitized)->not->toHaveKey('platforms'); expect($sanitized)->not->toHaveKey('settings'); });