import { readFile } from 'fs/promises'; import path from 'path'; import { parseDocument } from 'yaml'; import { ValidationError } from 'yup'; import { ValidateOptions } from 'yup/lib/types'; import { AUTHOR_SCHEMA } from '../author.schema'; async function loadYAML(filepath: string): Promise { const fileContents = await readFile( path.resolve(__dirname, filepath), 'utf8', ); const document = parseDocument(fileContents); return document.toJSON(); } const VALIDATION_OPTIONS: ValidateOptions = { strict: true, }; describe('author schema', function () { describe('on a valid file', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/valid.yaml'); }); it('passes', async function () { return expect( AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS), ).resolves.toEqual({ slug: 'patrick-mcallister.eth', name: 'Patrick McAllister', email: 'author@example.com', bio: 'This is my bio.', contacts: [ { service: 'website', link: 'https://example.com/', }, { service: 'twitter', link: 'https://twitter.com/a_user', }, { service: 'instagram', link: 'https://www.instagram.com/a_user/', }, ], series: ['a-sign-of-protest'], }); }); }); describe('slug', function () { describe('when the slug is missing', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/slug-missing.yaml'); }); it('fails validation with message "slug is a required field" and path "slug"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('slug is a required field'); expect(err.path).toEqual('slug'); } }); }); describe('when the slug is an empty string', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/slug-empty.yaml'); }); it('fails validation with message "slug is a required field" and path "slug"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('slug is a required field'); expect(err.path).toEqual('slug'); } }); }); describe('when the slug is mixed case', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/slug-mixedcase.yaml'); }); it('fails validation with message "slug must be a lowercase string" and path "slug"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('slug must be a lowercase string'); expect(err.path).toEqual('slug'); } }); }); describe('when the slug is a non-ens string', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/slug-nonens.yaml'); }); it('fails validation with message "slug must match the following" and path "slug"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe( 'slug must match the following: "/^[a-z0-9-]+\\.eth$/"', ); expect(err.path).toEqual('slug'); } }); }); }); describe('name', function () { describe('when the name is missing', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/name-missing.yaml'); }); it('fails validation with message "name is a required field" and path "name"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('name is a required field'); expect(err.path).toEqual('name'); } }); }); describe('when the name is an empty string', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/name-empty.yaml'); }); it('fails validation with message "name is a required field" and path "name"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('name is a required field'); expect(err.path).toEqual('name'); } }); }); }); describe('email', function () { describe('when the email is missing', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/email-missing.yaml'); }); it('fails validation with message "email is a required field" and path "email"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('email is a required field'); expect(err.path).toEqual('email'); } }); }); describe('when the email is an empty string', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/email-empty.yaml'); }); it('fails validation with message "email is a required field" and path "email"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('email is a required field'); expect(err.path).toEqual('email'); } }); }); describe('when the email is malformed', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/email-malformed.yaml'); }); it('fails validation with message "email must match the following" and path "email"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('email must be a valid email'); expect(err.path).toEqual('email'); } }); }); }); describe('series', function () { describe('when the series contains an empty string', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/series-empty.yaml'); }); it('fails validation with message "series[0] is a required field" and path "series"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('series[0] is a required field'); expect(err.path).toEqual('series[0]'); } }); describe('when the series is mixedcase', function () { let data: unknown; beforeEach(async function () { data = await loadYAML('./fixtures/series-mixedcase.yaml'); }); it('fails validation with message "series[0] must be a lowercase string" and path "series"', async function () { expect.assertions(3); try { await AUTHOR_SCHEMA.validate(data, VALIDATION_OPTIONS); } catch (err) { if (!(err instanceof ValidationError)) { throw err; } expect(err).toBeInstanceOf(ValidationError); expect(err.message).toBe('series[0] must be a lowercase string'); expect(err.path).toEqual('series[0]'); } }); }); }); }); });