Codeception: Optionnal key for seeResponseMatchesJsonType method

Created on 26 Jan 2017  路  6Comments  路  Source: Codeception/Codeception

Hi,

I'm trying to use the seeResponseMatchesJsonType methode in order to check the structure of my returned json, but I have some optional keys which seems to cause problem.

For example, I have tried the following :

$I->seeResponseMatchesJsonType([
'id' => 'string',
'rank' => 'array|null'
],);

But I get the following error : Key rank doesn't exist in

Is there a way to specify that my key is optional ? Meaning that if present, it has to be an array, if not present, it's ok.

Thanks,
Julien

Most helpful comment

Same problem. Array can containst key 'leaf' => true, or 'children' => array insteed. Both variants can exist in one test and both valid. Help, please.

All 6 comments

Anyone ?

Have 2 different tests for cases when the key is present and when it is missing.

Same problem. Array can containst key 'leaf' => true, or 'children' => array insteed. Both variants can exist in one test and both valid. Help, please.

As I see, if I send the parameter with null value, it works, but as @pesseyjulien if I not send the parameter, then says that the key does not exist

tried with version 2.4.1

$jsonType = new JsonType([
    'a' => 1
]);
echo $jsonType->matches([
    'a' => 'integer',
    'b' => 'integer|null'
]);

// Key `b` doesn't exist in {"a":1}

I modified this method in typeComparison and does the trick, just add the type 'opt'. Also you can have optional values, that cannot be null

protected function typeComparison($data, $jsonType)
    {
        foreach ($jsonType as $key => $type) {
            $matchTypes  = preg_split("#(?![^]\(]*\))\|#", $type);

            if (!array_key_exists($key, $data) && !in_array('opt', $matchTypes, true)) {
                return "Key `$key` doesn't exist in " . json_encode($data);
            }

            if (is_array($jsonType[$key])) {
                $message = $this->typeComparison($data[$key], $jsonType[$key]);
                if (is_string($message)) {
                    return $message;
                }
                continue;
            }

            $matched     = false;
            $currentType = strtolower(gettype($data[$key] ?? null));
            if ($currentType === 'double') {
                $currentType = 'float';
            }
            foreach ($matchTypes as $matchType) {
                $filters      = preg_split("#(?![^]\(]*\))\:#", $matchType);
                $expectedType = strtolower(trim(array_shift($filters)));

                if ($expectedType !== $currentType && !($expectedType === 'opt' && $currentType === 'null')) {
                    continue;
                }

                $matched = true;

                foreach ($filters as $filter) {
                    $matched = $matched && $this->matchFilter($filter, $data[$key]);
                }
                if ($matched) {
                    break;
                }
            }
            if (!$matched) {
                return sprintf("`$key: %s` is of type `$type`", var_export($data[$key] ?? null, true));
            }
        }

        return true;
    }
$jsonType = new JsonType([
    'a' => 1
]);
$jsonType->matches([
    'a' => 'integer',
    'b' => 'integer|opt'
]);
// true

@pesseyjulien since Codeception 4, you can use seeResponseIsValidOnJsonSchema() function that will check if your response is valid on JsonSchema provided. In schema you can define multiple possible types as:
{ "type": ["integer", "string"] }

Was this page helpful?
0 / 5 - 0 ratings