build static method

Map<String, dynamic> build()

Implementation

static Map<String, dynamic> build() {
  final defs = <String, dynamic>{
    'mockResponse': {
      'type': 'object',
      'additionalProperties': false,
      'properties': {
        'statusCode': {'type': 'integer'},
        'body': true,
        'headers': {
          'type': 'object',
          'additionalProperties': true,
        },
      },
    },
    'mockApiEntry': {
      'type': 'object',
      'additionalProperties': false,
      'properties': {
        'response': {'\$ref': '#/\$defs/mockResponse'},
        'delayMs': {'type': 'integer'},
      },
      'required': ['response'],
    },
    'initialState': {
      'type': 'object',
      'additionalProperties': false,
      'properties': {
        'storage': {'type': 'object', 'additionalProperties': true},
        'env': {'type': 'object', 'additionalProperties': true},
      },
    },
    'mocks': {
      'type': 'object',
      'additionalProperties': false,
      'properties': {
        'apis': {
          'type': 'object',
          'additionalProperties': {'\$ref': '#/\$defs/mockApiEntry'},
        },
      },
    },
    'testCase': {
      'type': 'object',
      'additionalProperties': false,
      'properties': {
        'id': {
          'type': 'string',
          'minLength': 1,
          'description': 'Unique test identifier',
        },
        'type': {'type': 'string'},
        'feature': {
          'type': 'string',
          'minLength': 1,
          'description': 'Feature or flow name, e.g. login or wifi',
        },
        'tags': {
          'type': 'array',
          'items': {'type': 'string'},
          'description': 'Free-form labels for filtering and organization',
        },
        'description': {'type': 'string'},
        'owner': {'type': 'string'},
        'priority': {
          'type': 'string',
          'enum': [
            'p0',
            'p1',
            'p2',
            'p3',
            'critical',
            'high',
            'medium',
            'low'
          ],
        },
        'startScreen': {
          'type': 'string',
          'minLength': 1,
          'description': 'Ensemble screen name or id to load first',
        },
        'prerequisite': {
          'type': 'string',
          'minLength': 1,
          'description':
              'ID of another test that must run before this one in the same app session',
        },
        'initialState': {'\$ref': '#/\$defs/initialState'},
        'mocks': {'\$ref': '#/\$defs/mocks'},
        'steps': {
          'type': 'array',
          'minItems': 1,
          'items': {'\$ref': '#/\$defs/step'},
        },
      },
      'required': ['id', 'steps'],
      'oneOf': [
        {
          'required': ['startScreen'],
          'not': {
            'required': ['prerequisite'],
          },
        },
        {
          'required': ['prerequisite'],
          'not': {
            'required': ['startScreen'],
          },
        },
      ],
    },
  };

  // Register per-step arg defs and step wrappers.
  final stepOneOf = <Map<String, dynamic>>[];
  final registeredArgDefs = <String>{};

  for (final yamlKey in TestStepVocabulary.yamlStepKeys) {
    final entry = TestStepRegistry.entries[yamlKey]!;
    final description = entry.description;
    final argsSchema = TestStepVocabulary.argJsonSchemaForYamlKey(yamlKey);
    final argsDefName = 'args_$yamlKey';

    final exampleArgs = Map<String, dynamic>.from(entry.example);
    final exampleStep = {yamlKey: exampleArgs};

    if (registeredArgDefs.add(argsDefName)) {
      defs[argsDefName] = {
        ...argsSchema,
        'title': yamlKey,
        'description': description,
        'examples': [exampleArgs],
      };
    }

    stepOneOf.add({
      'type': 'object',
      'title': yamlKey,
      'description': description,
      'examples': [exampleStep],
      'additionalProperties': false,
      'minProperties': 1,
      'maxProperties': 1,
      'properties': {
        yamlKey: {
          '\$ref': '#/\$defs/$argsDefName',
          'description': description,
          'examples': [exampleArgs],
        },
      },
      'required': [yamlKey],
    });
  }

  defs['step'] = {'oneOf': stepOneOf};

  final testCase = defs.remove('testCase') as Map<String, dynamic>;

  return {
    '\$schema': schemaVersion,
    '\$id': schemaId,
    'title': 'Ensemble declarative test file',
    'description':
        'Schema for app-local tests/*.test.yaml — one test per file; '
            'see packages/ensemble_test_runner/STEP_VOCABULARY.md',
    ...testCase,
    '\$defs': defs,
  };
}