zod#ZodError TypeScript Examples

The following examples show how to use zod#ZodError. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ois.test.ts    From airnode with MIT License 6 votes vote down vote up
describe('disallows reserved parameter name', () => {
  it('in operation parameters', () => {
    expect(() => operationParameterSchema.parse({ in: 'header', name: '_type' })).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: '"_type" cannot be used because it is a name of a reserved parameter',
          path: ['name'],
        },
      ])
    );
  });

  it('in parameters', () => {
    expect(() =>
      endpointParameterSchema.parse({ name: 'param', operationParameter: { in: 'header', name: '_type' } })
    ).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: '"_type" cannot be used because it is a name of a reserved parameter',
          path: ['operationParameter', 'name'],
        },
      ])
    );
  });
});
Example #2
Source File: config.test.ts    From nft-tutorial with MIT License 6 votes vote down vote up
describe('tznft configuration tests', () => {
  let config: Config;

  beforeEach(async () => {
    await initConfig();
  });

  afterEach(async () => {
    fs.unlink('./tznft.json');
  });

  test('Test successful reading and writing config.', async () => {
    let c = await loadConfig();

    const alias = {
      address: 'tz1YPSCGWXwBdTncK2aCctSZAXWvGsGwVJqU'
    };

    activeNetwork(c).aliases['test'] = alias;

    await saveConfig(c);
    c = await loadConfig();

    expect(activeNetwork(c).aliases['test']).toMatchObject(alias);
  });

  test('Test failure when reading config with an invalid address.', async () => {
    let c = await loadConfig();

    const alias = {
      address: 'tzInvalid'
    };

    activeNetwork(c).aliases['test'] = alias;

    await saveConfig(c);
    await expect(loadConfig()).rejects.toThrow(ZodError);
  });
});
Example #3
Source File: receipt.test.ts    From airnode with MIT License 6 votes vote down vote up
describe('receiptSchema', () => {
  const receipt = JSON.parse(readFileSync(join(__dirname, '../../test/fixtures/receipt.valid.json')).toString());

  it(`doesn't allow mismatch between Airnode short addresses`, () => {
    expect(() => receiptSchema.parse(receipt)).not.toThrow();

    const invalidReceipt = { ...receipt, deployment: { ...receipt.deployment, airnodeAddressShort: 'abcdef0' } };
    expect(() => receiptSchema.parse(invalidReceipt)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `Airnode short addresses don't match`,
          path: ['airnodeWallet', 'airnodeAddressShort'],
        },
      ])
    );
  });
});
Example #4
Source File: receipt.test.ts    From airnode with MIT License 6 votes vote down vote up
describe('airnodeWalletSchema', () => {
  const airnodeWallet: AirnodeWallet = {
    airnodeAddress: '0xA30CA71Ba54E83127214D3271aEA8F5D6bD4Dace',
    airnodeAddressShort: 'a30ca71',
    airnodeXpub:
      'xpub6C8tvRgYkjNVaGMtpyZf4deBcUQHf7vgWUraVxY6gYiZhBYbPkFkLLWJzUUeVFdkKpVtatmXHX8kB76xgfmTpVZWbVWdq1rneaAY6a8RtbY',
  };

  it(`doesn't allow invalid Airnode address`, () => {
    expect(() => airnodeWalletSchema.parse(airnodeWallet)).not.toThrow();

    const invalidAirnodeWallet = { ...airnodeWallet, airnodeAddress: 'not-a-valid-address' };
    expect(() => airnodeWalletSchema.parse(invalidAirnodeWallet)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'Airnode address is not a valid address',
          path: ['airnodeAddress'],
        },
      ])
    );
  });

  it(`doesn't allow mismatch between Airnode address and Airnode short address`, () => {
    expect(() => airnodeWalletSchema.parse(airnodeWallet)).not.toThrow();

    const invalidAirnodeWallet = { ...airnodeWallet, airnodeAddressShort: 'abcdef0' };
    expect(() => airnodeWalletSchema.parse(invalidAirnodeWallet)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `Short Airnode address doesn't match Airnode address`,
          path: ['airnodeAddressShort'],
        },
      ])
    );
  });
});
Example #5
Source File: receipt.test.ts    From airnode with MIT License 6 votes vote down vote up
it(`doesn't allow extraneous properties`, () => {
  const receipt = JSON.parse(readFileSync(join(__dirname, '../../test/fixtures/receipt.valid.json')).toString());
  expect(() => receiptSchema.parse(receipt)).not.toThrow();

  const invalidReceipt = { ...receipt, unknownProp: 'someValue' };
  expect(() => receiptSchema.parse(invalidReceipt)).toThrow(
    new ZodError([
      {
        code: 'unrecognized_keys',
        keys: ['unknownProp'],
        path: [],
        message: `Unrecognized key(s) in object: 'unknownProp'`,
      },
    ])
  );
});
Example #6
Source File: ois.test.ts    From airnode with MIT License 6 votes vote down vote up
it('fails if apiSpecifications.security.<securitySchemeName> is not defined in apiSpecifications.components.<securitySchemeName>', () => {
  const invalidSecuritySchemeName = 'INVALID_SECURITY_SCHEME_NAME';
  const ois = loadOisFixture();
  const invalidOis = {
    ...ois,
    ...{
      apiSpecifications: {
        ...ois.apiSpecifications,
        security: { ...ois.apiSpecifications.security, [invalidSecuritySchemeName]: [] },
      },
    },
  };

  expect(() => oisSchema.parse(invalidOis)).toThrow(
    new ZodError([
      {
        code: 'custom',
        message: `Security scheme "${invalidSecuritySchemeName}" is not defined in "components.securitySchemes"`,
        path: ['apiSpecifications', 'security', 1],
      },
    ])
  );
});
Example #7
Source File: ois.test.ts    From airnode with MIT License 6 votes vote down vote up
it('handles discriminated union error nicely', () => {
  const ois = loadOisFixture();
  delete (ois.apiSpecifications.components.securitySchemes.coinlayerSecurityScheme as any).name;

  expect(() => oisSchema.parse(ois)).toThrow(
    new ZodError([
      {
        code: 'invalid_type',
        expected: 'string',
        received: 'undefined',
        path: ['apiSpecifications', 'components', 'securitySchemes', 'coinlayerSecurityScheme', 'name'],
        message: 'Required',
      },
    ])
  );
});
Example #8
Source File: ois.test.ts    From airnode with MIT License 6 votes vote down vote up
it(`doesn't allow extraneous properties`, () => {
  const ois = JSON.parse(readFileSync(join(__dirname, '../../test/fixtures/ois.json')).toString());
  expect(() => oisSchema.parse(ois)).not.toThrow();

  const invalidois = { ...ois, unknownProp: 'someValue' };
  expect(() => oisSchema.parse(invalidois)).toThrow(
    new ZodError([
      {
        code: 'unrecognized_keys',
        keys: ['unknownProp'],
        path: [],
        message: `Unrecognized key(s) in object: 'unknownProp'`,
      },
    ])
  );
});
Example #9
Source File: config.test.ts    From airnode with MIT License 6 votes vote down vote up
it('fails if a securitySchemeName is enabled and it is of type "apiKey" or "http" but is missing credentials in "apiCredentials"', () => {
  const config: Config = JSON.parse(
    readFileSync(join(__dirname, '../../test/fixtures/interpolated-config.valid.json')).toString()
  );

  const securitySchemeName = 'Currency Converter Security Scheme';
  const securityScheme = {
    [securitySchemeName]: {
      in: 'query',
      type: 'apiKey',
      name: 'access_key',
    },
  };
  const invalidConfig = {
    ...config,
    ois: [
      ...config.ois,
      {
        ...config.ois[0],
        apiSpecifications: {
          ...config.ois[0].apiSpecifications,
          components: { securitySchemes: securityScheme },
          security: { [securitySchemeName]: [] },
        },
      },
    ],
    apiCredentials: [],
  };

  expect(() => configSchema.parse(invalidConfig)).toThrow(
    new ZodError([
      {
        code: 'custom',
        message: 'The security scheme is enabled but no credentials are provided in "apiCredentials"',
        path: ['ois', 1, 'apiSpecifications', 'security', securitySchemeName],
      },
    ])
  );
});
Example #10
Source File: config.test.ts    From airnode with MIT License 6 votes vote down vote up
describe('templates', () => {
  it('does not allow invalid templates', () => {
    const config = JSON.parse(
      readFileSync(join(__dirname, '../../test/fixtures/interpolated-config.valid.json')).toString()
    );
    const invalidTemplates = [
      {
        // invalid templateId
        templateId: '0x38ba0e80224f14d0c654c4ba6e3745fcb7f310fd4f2f80994fe802da013edaff',
        endpointId: '0x13dea3311fe0d6b84f4daeab831befbc49e19e6494c41e9e065a09c3c68f43b6',
        encodedParameters: '0x6874656d706c6174656576616c7565',
      },
    ];

    expect(() => configSchema.parse({ ...config, templates: invalidTemplates })).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `Template is invalid`,
          path: ['0x38ba0e80224f14d0c654c4ba6e3745fcb7f310fd4f2f80994fe802da013edaff'],
        },
      ])
    );
  });
});
Example #11
Source File: config.test.ts    From airnode with MIT License 6 votes vote down vote up
it(`doesn't allow extraneous properties`, () => {
  const config = JSON.parse(
    readFileSync(join(__dirname, '../../test/fixtures/interpolated-config.valid.json')).toString()
  );
  expect(() => configSchema.parse(config)).not.toThrow();

  const invalidConfig = { ...config, unknownProp: 'someValue' };
  expect(() => configSchema.parse(invalidConfig)).toThrow(
    new ZodError([
      {
        code: 'unrecognized_keys',
        keys: ['unknownProp'],
        path: [],
        message: `Unrecognized key(s) in object: 'unknownProp'`,
      },
    ])
  );
});
Example #12
Source File: config.test.ts    From airnode with MIT License 5 votes vote down vote up
describe('triggers references', () => {
  const config: Config = JSON.parse(
    readFileSync(join(__dirname, '../../test/fixtures/interpolated-config.valid.json')).toString()
  );

  it(`fails if an OIS referenced in a trigger doesn't exist`, () => {
    const invalidConfig = {
      ...config,
      triggers: {
        ...config.triggers,
        rrp: [{ ...config.triggers.rrp[0], oisTitle: 'nonExistingOis' }],
      },
    };

    expect(() => configSchema.parse(invalidConfig)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `No matching OIS for trigger with OIS title "nonExistingOis"`,
          path: ['triggers', 'rrp', 0, 'oisTitle'],
        },
      ])
    );
  });

  it(`fails if an endpoint referenced in a trigger doesn't exist`, () => {
    const invalidConfig = {
      ...config,
      triggers: {
        ...config.triggers,
        rrp: [{ ...config.triggers.rrp[0], endpointName: 'nonExistingEndpointName' }],
      },
    };

    expect(() => configSchema.parse(invalidConfig)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `No matching endpoint for trigger with endpoint name "nonExistingEndpointName"`,
          path: ['triggers', 'rrp', 0, 'endpointName'],
        },
      ])
    );
  });
});
Example #13
Source File: ois.test.ts    From airnode with MIT License 5 votes vote down vote up
it('verifies parameter interpolation in "apiSpecification.paths"', () => {
  const ois = loadOisFixture();
  ois.apiSpecifications.paths['/someEndpoint/{id1}/{id2}'] = {
    get: {
      parameters: [
        {
          in: 'path',
          name: 'id1',
        },
      ],
    },
    post: {
      parameters: [
        {
          in: 'path',
          name: 'id2',
        },
        {
          in: 'path',
          name: 'id3',
        },
      ],
    },
  };

  expect(() => oisSchema.parse(ois)).toThrow(
    new ZodError([
      {
        code: 'custom',
        message: 'Path parameter "id2" is not found in "parameters"',
        path: ['apiSpecifications', 'paths', '/someEndpoint/{id1}/{id2}', 'get', 'parameters'],
      },
      {
        code: 'custom',
        message: 'Path parameter "id1" is not found in "parameters"',
        path: ['apiSpecifications', 'paths', '/someEndpoint/{id1}/{id2}', 'post', 'parameters'],
      },
      {
        code: 'custom',
        message: 'Parameter "id3" is not found in the URL path',
        path: ['apiSpecifications', 'paths', '/someEndpoint/{id1}/{id2}', 'post', 'parameters', 1],
      },
    ])
  );
});
Example #14
Source File: config.test.ts    From airnode with MIT License 5 votes vote down vote up
describe('nodeSettingsSchema', () => {
  const nodeSettings: NodeSettings = {
    cloudProvider: {
      type: 'local',
    },
    airnodeWalletMnemonic: 'test test test test test test test test test test test junk',
    heartbeat: {
      enabled: false,
    },
    httpGateway: {
      enabled: false,
    },
    httpSignedDataGateway: {
      enabled: false,
    },
    logFormat: 'plain',
    logLevel: 'INFO',
    nodeVersion: packageVersion,
    stage: 'dev',
  };

  it('must match package version', () => {
    expect(() => nodeSettingsSchema.parse(nodeSettings)).not.toThrow();

    const invalidNodeSettings = { ...nodeSettings, nodeVersion: '0.4.0' };
    expect(() => nodeSettingsSchema.parse(invalidNodeSettings)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `The "nodeVersion" must be ${packageVersion}`,
          path: ['nodeVersion'],
        },
      ])
    );
  });

  it('does not allow same gateway keys on AWS', () => {
    const invalidNodeSettings = {
      ...nodeSettings,
      cloudProvider: {
        type: 'aws',
        region: 'region',
        disableConcurrencyReservations: false,
      },
      httpGateway: {
        enabled: true,
        apiKey: 'sameApiKey',
        maxConcurrency: 10,
      },
      httpSignedDataGateway: {
        enabled: true,
        apiKey: 'sameApiKey',
        maxConcurrency: 10,
      },
    };

    expect(() => nodeSettingsSchema.parse(invalidNodeSettings)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `Using the same gateway keys is not allowed on AWS`,
          path: [],
        },
      ])
    );
  });

  it('is ok if both gateways are disabled on AWS', () => {
    const invalidNodeSettings = {
      ...nodeSettings,
      cloudProvider: {
        type: 'aws',
        region: 'region',
        disableConcurrencyReservations: false,
      },
    };

    expect(() => nodeSettingsSchema.parse(invalidNodeSettings)).not.toThrow();
  });
});
Example #15
Source File: receipt.test.ts    From airnode with MIT License 5 votes vote down vote up
describe('deploymentSchema', () => {
  const deployment: Deployment = {
    airnodeAddressShort: 'a30ca71',
    cloudProvider: {
      type: 'aws',
      region: 'us-east-1',
      disableConcurrencyReservations: false,
    },
    stage: 'starter-example',
    nodeVersion: packageVersion,
    timestamp: '2022-05-18T06:37:35.507Z',
  };

  it('must match package version', () => {
    expect(() => deploymentSchema.parse(deployment)).not.toThrow();

    const invalidDeployment = { ...deployment, nodeVersion: '0.4.0' };
    expect(() => deploymentSchema.parse(invalidDeployment)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: `The "nodeVersion" must be ${packageVersion}`,
          path: ['nodeVersion'],
        },
      ])
    );
  });

  it(`doesn't allow stage in a wrong format`, () => {
    expect(() => deploymentSchema.parse(deployment)).not.toThrow();

    const invalidDeployment01 = { ...deployment, stage: 'stagenamewaytoolong' };
    expect(() => deploymentSchema.parse(invalidDeployment01)).toThrow(
      new ZodError([
        {
          validation: 'regex',
          code: 'invalid_string',
          message: 'Invalid',
          path: ['stage'],
        },
      ])
    );

    const invalidDeployment02 = { ...deployment, stage: 'STAGE%^&*' };
    expect(() => deploymentSchema.parse(invalidDeployment02)).toThrow(
      new ZodError([
        {
          validation: 'regex',
          code: 'invalid_string',
          message: 'Invalid',
          path: ['stage'],
        },
      ])
    );
  });

  it(`doesn't allow timestamp in a wrong format`, () => {
    expect(() => deploymentSchema.parse(deployment)).not.toThrow();

    const invalidDeployment = { ...deployment, timestamp: 'invalid_timestamp' };
    expect(() => deploymentSchema.parse(invalidDeployment)).toThrow(
      new ZodError([
        {
          validation: 'regex',
          code: 'invalid_string',
          message: 'Invalid',
          path: ['timestamp'],
        },
      ])
    );
  });
});
Example #16
Source File: config.test.ts    From airnode with MIT License 5 votes vote down vote up
describe('chainOptionsSchema', () => {
  const eip1559ChainOptions: ChainOptions = {
    txType: 'eip1559',
    baseFeeMultiplier: 2,
    priorityFee: {
      value: 3.12,
      unit: 'gwei',
    },
    fulfillmentGasLimit: 500000,
  };

  const legacyChainOptions: ChainOptions = {
    txType: 'legacy',
    gasPriceMultiplier: 1.1,
    fulfillmentGasLimit: 500000,
  };

  it('does not allow legacy chain options for eip1559 transactions', () => {
    expect(() => chainOptionsSchema.parse(eip1559ChainOptions)).not.toThrow();

    const invalidEip1559Settings = { ...eip1559ChainOptions, gasPriceMultiplier: 2 };
    expect(() => chainOptionsSchema.parse(invalidEip1559Settings)).toThrow(
      new ZodError([
        {
          code: 'unrecognized_keys',
          keys: ['gasPriceMultiplier'],
          path: [],
          message: `Unrecognized or disallowed key(s) for the given transaction type: 'gasPriceMultiplier'`,
        },
      ])
    );
  });

  it('does not allow eip1559 chain options for legacy transactions', () => {
    expect(() => chainOptionsSchema.parse(legacyChainOptions)).not.toThrow();

    const invalidLegacySettings = { ...legacyChainOptions, baseFeeMultiplier: 2, priorityFee: 3.12 };
    expect(() => chainOptionsSchema.parse(invalidLegacySettings)).toThrow(
      new ZodError([
        {
          code: 'unrecognized_keys',
          keys: ['baseFeeMultiplier', 'priorityFee'],
          path: [],
          message: `Unrecognized or disallowed key(s) for the given transaction type: 'baseFeeMultiplier', 'priorityFee'`,
        },
      ])
    );
  });
});
Example #17
Source File: validation.test.ts    From xrp-batch-payout-cli with Apache License 2.0 4 votes vote down vote up
// The main focus of these tests is malformatted CSV input, as
// we don't want a successful payments run to be triggered, but malformatted
// output to be generated
describe('Integration Tests - Input Validation', function () {
  before(async function () {
    // Get prompt overrides for tests
    const overridePath = path.join(__dirname, '.', 'data', 'override.json')
    this.overrides = JSON.parse(
      (await fs.promises.readFile(overridePath)).toString(),
    )
  })

  beforeEach(async function () {
    // Remove the output CSV if it exists
    // eslint-disable-next-line node/no-sync -- This method is not deprecated anymore, we expect this to be synchronous.
    if (fs.existsSync(this.overrides.outputCsv)) {
      await fs.promises.unlink(this.overrides.outputCsv)
    }
  })

  it('Throws on an input CSV that does not exist', async function () {
    this.overrides.inputCsv = './file_does_not_exist'
    try {
      await payout(this.overrides)
    } catch (err) {
      assert(err instanceof ZodError)
      if (err instanceof ZodError) {
        assert(err.errors[0].path[0] === 'inputCsv')
      }
    }
  })

  it('Throws on an input CSV containing a malformatted classic address', async function () {
    const inputCsvPath = path.join(
      __dirname,
      '.',
      'data',
      'malformatted',
      'bad_address.csv',
    )
    this.overrides.inputCsv = inputCsvPath
    try {
      await payout(this.overrides)
    } catch (err) {
      assert(err instanceof ZodError)
      if (err instanceof ZodError) {
        assert(err.errors[0].path[0] === 'address')
      }
    }
  })

  it('Throws on an input CSV with a missing name', async function () {
    const inputCsvPath = path.join(
      __dirname,
      '.',
      'data',
      'malformatted',
      'missing_name.csv',
    )
    this.overrides.inputCsv = inputCsvPath
    try {
      await payout(this.overrides)
    } catch (err) {
      assert(err instanceof ZodError)
      if (err instanceof ZodError) {
        assert(err.errors[0].path[0] === 'name')
      }
    }
  })

  it('Throws on an input CSV with a bad destination tag', async function () {
    const inputCsvPath = path.join(
      __dirname,
      '.',
      'data',
      'malformatted',
      'bad_tag.csv',
    )
    this.overrides.inputCsv = inputCsvPath
    try {
      await payout(this.overrides)
    } catch (err) {
      assert(err instanceof ZodError)
      if (err instanceof ZodError) {
        assert(err.errors[0].path[0] === 'destinationTag')
      }
    }
  })

  it('Throws on input CSV with malformatted headers', async function () {
    const inputCsvPath = path.join(
      __dirname,
      '.',
      'data',
      'malformatted',
      'bad_header.csv',
    )
    this.overrides.inputCsv = inputCsvPath
    try {
      await payout(this.overrides)
    } catch (err) {
      assert(err instanceof ZodError)
      if (err instanceof ZodError) {
        assert(err.errors[0].code === 'unrecognized_keys')
        assert(
          (err.errors[0] as ZodUnrecognizedKeysError).keys[0] ===
            'destinationTg',
        )
        assert(err.errors[1].path[0] === 'destinationTag')
      }
    }
  })
})
Example #18
Source File: processing.test.ts    From airnode with MIT License 4 votes vote down vote up
describe('processing', () => {
  describe('pre-processing', () => {
    it('valid processing code', async () => {
      const config = fixtures.buildConfig();
      const preProcessingSpecifications = [
        {
          environment: 'Node 14' as const,
          value: 'const output = {...input, from: "ETH"};',
          timeoutMs: 5_000,
        },
        {
          environment: 'Node 14' as const,
          value: 'const output = {...input, newProp: "airnode"};',
          timeoutMs: 5_000,
        },
      ];
      config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], preProcessingSpecifications };

      const parameters = { _type: 'int256', _path: 'price' };
      const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters });

      const result = await preProcessApiSpecifications({ config, aggregatedApiCall });

      expect(result.aggregatedApiCall.parameters).toEqual({
        _path: 'price',
        _type: 'int256',
        from: 'ETH',
        newProp: 'airnode',
      });
    });

    it('invalid processing code', async () => {
      const config = fixtures.buildConfig();
      const preProcessingSpecifications = [
        {
          environment: 'Node 14' as const,
          value: 'something invalid; const output = {...input, from: `ETH`};',
          timeoutMs: 5_000,
        },
        {
          environment: 'Node 14' as const,
          value: 'const output = {...input, newProp: "airnode"};',
          timeoutMs: 5_000,
        },
      ];
      config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], preProcessingSpecifications };

      const parameters = { _type: 'int256', _path: 'price', from: 'TBD' };
      const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters });

      const throwingFunc = async () => preProcessApiSpecifications({ config, aggregatedApiCall });

      await expect(throwingFunc).rejects.toEqual(new Error('Unexpected identifier'));
    });

    it('throws validation error if result does not have parameters shape', async () => {
      const config = fixtures.buildConfig();
      const preProcessingSpecifications = [
        {
          environment: 'Node 14' as const,
          value: 'const output = {...input, object: {a: 123, b: false}};',
          timeoutMs: 5_000,
        },
      ];
      config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], preProcessingSpecifications };

      const parameters = { _type: 'int256', _path: 'price', from: '*ETH' };
      const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters });

      const throwingFunc = async () => preProcessApiSpecifications({ config, aggregatedApiCall });

      await expect(throwingFunc).rejects.toEqual(
        new ZodError([
          {
            code: 'invalid_type',
            expected: 'string',
            received: 'object',
            path: ['object'],
            message: 'Expected string, received object',
          },
        ])
      );
    });
  });
});
Example #19
Source File: payout.ts    From xrp-batch-payout-cli with Apache License 2.0 4 votes vote down vote up
/**
 * Run the XRP payout script.
 *
 * @param override - Override prompt inputs. Useful for testing and debugging.
 * @throws Re-throws error after logging.
 */
export default async function payout(override?: unknown): Promise<void> {
  try {
    // Prompt user to configure XRP payout and validate user input
    const senderInput = await parseFromPromptToObject<SenderInput>(
      questions,
      senderInputSchema,
      override,
    )

    // Cancel if user did not confirm payout
    if (!senderInput.confirmed) {
      throw Error(red('XRP batch payout stopped.'))
    }

    log.info('Starting XRP batch payout..')

    // Parse and validate input CSV to get XRP transaction inputs
    log.info('')
    log.info(`Parsing data from ${senderInput.inputCsv}..`)
    const txInputReadStream = fs.createReadStream(senderInput.inputCsv)
    const txInputs = await parseFromCsvToArray<TxInput>(
      txInputReadStream,
      txInputSchema,
    )
    log.info(green(`Parsed and validated ${txInputs.length} entries.`))

    // Generate XRP wallet from secret
    log.info('')
    log.info(`Generating ${senderInput.network} wallet from secret..`)

    const wallet = Wallet.fromSecret(senderInput.secret)
    log.info(green('Generated wallet from secret.'))
    log.info(black(`  -> Sender XRPL X-Address: ${wallet.getXAddress()}`))
    log.info(black(`  -> Sender XRPL Classic address: ${wallet.classicAddress}`))

    // Connect to XRPL
    log.info('')
    log.info(`Connecting to XRPL ${senderInput.network}..`)
    
    log.info(green(`Connected to XRPL ${senderInput.network}.`))
    log.info(
      black(`  -> RippleD node WebSocket endpoint: ${senderInput.serverUrl}`),
    )

    const client = new Client(senderInput.serverUrl)
    await client.connect()
    log.info(green('Connected'))
    
    const balance = await client.getXrpBalance(wallet.classicAddress)
    log.info(black(`  -> ${wallet.classicAddress} balance: ${balance} XRP`))

    // Reliably send XRP to accounts specified in transaction inputs
    const txOutputWriteStream = fs.createWriteStream(senderInput.outputCsv)
    await reliableBatchPayment(
      txInputs,
      txOutputWriteStream,
      txOutputSchema,
      wallet,
      client,
      senderInput.usdToXrpRate,
    )

    log.info('')
    log.info(
      green(
        `Batch payout complete succeeded. Reliably sent ${txInputs.length} XRP payments.`,
      ),
    )
    await client.disconnect();

  } catch (err) {
    if (err instanceof ZodError) {
      log.error(err.errors)
    } else {
      log.error(err)
    }
    throw err
  }
}
Example #20
Source File: ois.test.ts    From airnode with MIT License 4 votes vote down vote up
describe('apiSpecification parameters validation', () => {
  it('fails if "apiSpecification.paths" parameter is not defined in "endpoints"', () => {
    const invalidOis = loadOisFixture();
    invalidOis.apiSpecifications.paths['/convert'].get!.parameters.push({
      in: 'query',
      name: 'non-existing-parameter',
    });

    expect(() => oisSchema.parse(invalidOis)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'Parameter "non-existing-parameter" not found in "fixedOperationParameters" or "parameters"',
          path: ['ois', 'endpoints', 0],
        },
      ])
    );
  });

  it('"endpoint" parameter must reference parameter from "apiSpecification.paths"', () => {
    const invalidOis = loadOisFixture();
    invalidOis.endpoints[0].parameters.push({
      name: 'some-new-param',
      default: 'EUR',
      operationParameter: {
        in: 'query',
        name: 'non-existing-param',
      },
    });

    expect(() => oisSchema.parse(invalidOis)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'No matching API specification parameter found in "apiSpecifications" section',
          path: ['ois', 'endpoints', 0, 'parameters', 3],
        },
      ])
    );
  });

  it('handles multiple endpoints for the same API specification', () => {
    const ois = loadOisFixture();
    ois.endpoints.push(cloneDeep(ois.endpoints[0]));
    ois.apiSpecifications.paths['/convert'].get!.parameters.push({
      in: 'query',
      name: 'api-param-name',
    });

    expect(() => oisSchema.parse(ois)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'Parameter "api-param-name" not found in "fixedOperationParameters" or "parameters"',
          path: ['ois', 'endpoints', 0],
        },
        {
          code: 'custom',
          message: 'Parameter "api-param-name" not found in "fixedOperationParameters" or "parameters"',
          path: ['ois', 'endpoints', 1],
        },
      ])
    );
  });

  it('fails when there is no matching API specification for endpoint', () => {
    const invalidOis = loadOisFixture();
    invalidOis.endpoints[0].parameters.push({
      operationParameter: {
        in: 'query',
        name: 'non-existent',
      },
      name: 'param-name',
    });

    expect(() => oisSchema.parse(invalidOis)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'No matching API specification parameter found in "apiSpecifications" section',
          path: ['ois', 'endpoints', 0, 'parameters', 3],
        },
      ])
    );
  });
});
Example #21
Source File: ois.test.ts    From airnode with MIT License 4 votes vote down vote up
describe('parameter uniqueness', () => {
  it('allows parameter with same name, but different location', () => {
    const paramName = 'some-id';
    const ois = loadOisFixture();
    ois.apiSpecifications.paths['/convert'].get!.parameters.push({
      in: 'query',
      name: paramName,
    });
    ois.endpoints[0].fixedOperationParameters.push({
      operationParameter: {
        in: 'query',
        name: paramName,
      },
      value: 'query-id',
    });
    ois.apiSpecifications.paths['/convert'].get!.parameters.push({
      in: 'cookie',
      name: paramName,
    });
    ois.endpoints[0].fixedOperationParameters.push({
      operationParameter: {
        in: 'cookie',
        name: paramName,
      },
      value: 'cookie-id',
    });

    expect(() => oisSchema.parse(ois)).not.toThrow();
  });

  it(`fails if the same parameter is used in "parameters"`, () => {
    const ois = loadOisFixture();
    ois.endpoints[0].parameters.push(ois.endpoints[0].parameters[0] as any);

    expect(() => oisSchema.parse(ois)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'Parameter "from" in "query" is used multiple times',
          path: ['ois', 'endpoints', 0, 'parameters', 0],
        },
        {
          code: 'custom',
          message: 'Parameter "from" in "query" is used multiple times',
          path: ['ois', 'endpoints', 0, 'parameters', 3],
        },
      ])
    );
  });

  it(`fails if the same parameter is used in "fixedOperationParameters"`, () => {
    const ois = loadOisFixture();
    ois.endpoints[0].fixedOperationParameters.push(ois.endpoints[0].fixedOperationParameters[0] as any);

    expect(() => oisSchema.parse(ois)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'Parameter "to" in "query" is used multiple times',
          path: ['ois', 'endpoints', 0, 'fixedOperationParameters', 0],
        },
        {
          code: 'custom',
          message: 'Parameter "to" in "query" is used multiple times',
          path: ['ois', 'endpoints', 0, 'fixedOperationParameters', 1],
        },
      ])
    );
  });

  it('fails if the same parameter is used in both "fixedOperationParameters" and "parameters"', () => {
    const ois = loadOisFixture();
    ois.endpoints[0].fixedOperationParameters.push({
      operationParameter: ois.endpoints[0].parameters[0].operationParameter,
      value: '123',
    });

    expect(() => oisSchema.parse(ois)).toThrow(
      new ZodError([
        {
          code: 'custom',
          message: 'Parameter "from" in "query" is used in both "parameters" and "fixedOperationParameters"',
          path: ['ois', 'endpoints', 0, 'parameters', 0],
        },
        {
          code: 'custom',
          message: 'Parameter "from" in "query" is used in both "parameters" and "fixedOperationParameters"',
          path: ['ois', 'endpoints', 0, 'fixedOperationParameters', 1],
        },
      ])
    );
  });
});