Split and update tests
This commit is contained in:
@@ -1,211 +0,0 @@
|
||||
import {expect, test, describe, beforeEach, afterEach} from 'bun:test'
|
||||
import {yup} from '../src/index'
|
||||
import {type FileResult, fileSync} from 'tmp'
|
||||
import * as fs from 'node:fs/promises'
|
||||
|
||||
import * as parsing from '../src/parsing'
|
||||
import {parse} from '../src'
|
||||
|
||||
beforeEach(() => process.env = {})
|
||||
|
||||
async function testing(value: string | undefined, scheme: yup.AnySchema, should_be_successful: boolean, data?: unknown) {
|
||||
const key = 'DB_PORT'
|
||||
if (value !== undefined) process.env[key] = value
|
||||
|
||||
const res = await parsing.generic(scheme, key)
|
||||
|
||||
if (should_be_successful) expect(res).toEqual({ok: true, data})
|
||||
else expect(res.ok).not.toBeTrue()
|
||||
}
|
||||
|
||||
// Most important function : read_object
|
||||
describe('Object', () => {
|
||||
test('basic', async () => {
|
||||
const scheme = yup.object({})
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: {}})
|
||||
})
|
||||
test('One level', async () => {
|
||||
process.env = {
|
||||
NAME: 'test',
|
||||
PORT: '12',
|
||||
TS: '2025-06-08 23:51:12'
|
||||
}
|
||||
const scheme = yup.object({name: yup.string(), port: yup.number(), ts: yup.date()})
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: {name: 'test', port: 12, ts: new Date('2025-06-08 23:51:12')}})
|
||||
})
|
||||
test('Two levels', async () => {
|
||||
process.env = {
|
||||
DB_PORT: '12',
|
||||
DB_HOST: 'localhost',
|
||||
THING_A: 'Hello!',
|
||||
THING_B: '212',
|
||||
NAME: 'Pascal',
|
||||
AGE: '27',
|
||||
}
|
||||
const expected = {
|
||||
name: 'Pascal',
|
||||
age: 27,
|
||||
db: {
|
||||
port: 12,
|
||||
host: 'localhost'
|
||||
},
|
||||
thing: {
|
||||
a: 'Hello!',
|
||||
b: 212,
|
||||
}
|
||||
}
|
||||
|
||||
const scheme = yup.object({
|
||||
name: yup.string().required(),
|
||||
age: yup.number().required(),
|
||||
db: yup.object({
|
||||
port: yup.number().required(),
|
||||
host: yup.string().required()
|
||||
}).required(),
|
||||
thing: yup.object({
|
||||
a: yup.string().required(),
|
||||
b: yup.number().required(),
|
||||
}).required()
|
||||
})
|
||||
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: expected})
|
||||
|
||||
const res2 = await parse(scheme)
|
||||
expect(res.ok).toBeTrue()
|
||||
expect(res2.data).toEqual(expected)
|
||||
})
|
||||
test('Three levels', async () => {
|
||||
process.env = {
|
||||
DB_HOST: 'localhost',
|
||||
THING_A: 'Hello!',
|
||||
AGE: '27',
|
||||
THING_THANG_A: '2025-06-06 23:56:12'
|
||||
}
|
||||
const expected = {
|
||||
age: 27,
|
||||
db: {
|
||||
host: 'localhost'
|
||||
},
|
||||
thing: {
|
||||
a: 'Hello!',
|
||||
thang: {
|
||||
a: new Date('2025-06-06 23:56:12')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const scheme = yup.object({
|
||||
age: yup.number(),
|
||||
db: yup.object({
|
||||
host: yup.string()
|
||||
}),
|
||||
thing: yup.object({
|
||||
a: yup.string(),
|
||||
thang: yup.object({
|
||||
a: yup.date()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: expected})
|
||||
|
||||
const res2 = await parse(scheme)
|
||||
expect(res2.data).toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
||||
// Read any from file
|
||||
describe('from_file', () => {
|
||||
let file: FileResult | undefined = undefined;
|
||||
afterEach(() => {
|
||||
file?.removeCallback()
|
||||
file = undefined
|
||||
})
|
||||
|
||||
async function testing(value: string | undefined, scheme: yup.AnySchema, should_be_successful: boolean, data?: unknown) {
|
||||
file = fileSync()
|
||||
|
||||
const name = file.name
|
||||
if (value !== undefined) {
|
||||
await fs.writeFile(file.name, value)
|
||||
} else {
|
||||
file.removeCallback()
|
||||
file = undefined
|
||||
}
|
||||
|
||||
const key = 'DB_PORT'
|
||||
process.env[key + '__FILE'] = name
|
||||
|
||||
const res = await parsing.generic(scheme, key)
|
||||
|
||||
if (should_be_successful) expect(res).toEqual({ok: true, data})
|
||||
else expect(res.ok).not.toBeTrue()
|
||||
}
|
||||
|
||||
test('basic string', () => testing('Coucou', yup.string(), true, 'Coucou'))
|
||||
test('basic number', () => testing('12', yup.number(), true, 12))
|
||||
test('file does not exist', () => testing(undefined, yup.string(), false))
|
||||
test('Last empty line is trimmed', () => testing('Coucou\n\r\n ', yup.string(), true, 'Coucou'))
|
||||
})
|
||||
|
||||
// Read generic types
|
||||
describe('Integer', () => {
|
||||
test('basic', () => testing('12', yup.number(), true, 12))
|
||||
test('not present', () => testing(undefined, yup.number().required(), false))
|
||||
test('optional', () => testing(undefined, yup.number(), true))
|
||||
test('default', () => testing(undefined, yup.number().default(21), true, 21))
|
||||
test('string', () => testing('coucou', yup.number(), false))
|
||||
test('min-max OK', () => testing('12', yup.number().min(11).max(13), true, 12))
|
||||
test('min-max KO', () => testing('10', yup.number().min(11).max(13), false, 10))
|
||||
test('min-max KO 2', () => testing('10', yup.number().min(11).max(13), false, 14))
|
||||
})
|
||||
describe('String', () => {
|
||||
test('basic', () => testing('coucou', yup.string(), true, 'coucou'))
|
||||
test('not present', () => testing(undefined, yup.string().required(), false))
|
||||
test('optional', () => testing(undefined, yup.string(), true, undefined))
|
||||
test('default', () => testing(undefined, yup.string().default('yeet'), true, 'yeet'))
|
||||
test('Length min-max', () => testing('coucou', yup.string().max(7), true, 'coucou'))
|
||||
test('KO: Length min-max', () => testing('coucou', yup.string().max(5), false))
|
||||
})
|
||||
describe('boolean', () => {
|
||||
test('basic true', () => testing('true', yup.boolean(), true, true))
|
||||
test('basic 1', () => testing('1', yup.boolean(), true, true))
|
||||
test('basic 0', () => testing('0', yup.boolean(), true, false))
|
||||
test('not present', () => testing(undefined, yup.boolean().required(), false))
|
||||
test('optional', () => testing(undefined, yup.boolean(), true))
|
||||
test('default', () => testing(undefined, yup.boolean().default(false), true, false))
|
||||
})
|
||||
|
||||
// Read specific types
|
||||
describe('Date', () => {
|
||||
async function testing(value: string | undefined, scheme: yup.DateSchema, should_be_successful: boolean, data?: unknown) {
|
||||
const key = 'DB_PORT'
|
||||
if (value !== undefined) process.env[key] = value
|
||||
|
||||
const res = await parsing.generic(scheme, key)
|
||||
|
||||
if (should_be_successful) {
|
||||
expect(res).toEqual({ok: true, data})
|
||||
} else {
|
||||
expect(res).toEqual({ok: false})
|
||||
}
|
||||
}
|
||||
|
||||
test('basic', () => testing('2025-06-08 22:40:17', yup.date(), true, new Date('2025-06-08 22:40:17')))
|
||||
test('optional', () => testing(undefined, yup.date(), true))
|
||||
})
|
||||
describe('Array', () => {
|
||||
test('basic', () => testing('12,13,14', yup.array(yup.number()), true, [12,13,14]))
|
||||
/*test('not present', () => testing(undefined, yup.number().required(), false))
|
||||
test('optional', () => testing(undefined, yup.number(), true))
|
||||
test('default', () => testing(undefined, yup.number().default(21), true, 21))
|
||||
test('string', () => testing('coucou', yup.number(), false))
|
||||
test('min-max OK', () => testing('12', yup.number().min(11).max(13), true, 12))
|
||||
test('min-max KO', () => testing('10', yup.number().min(11).max(13), false, 10))
|
||||
test('min-max KO 2', () => testing('10', yup.number().min(11).max(13), false, 14))*/
|
||||
})
|
||||
describe.todo('Tuple')
|
||||
@@ -0,0 +1,57 @@
|
||||
import {test, describe, afterEach, beforeEach, expect} from 'bun:test'
|
||||
import {type FileResult, fileSync, dirSync, type DirResult} from 'tmp'
|
||||
import * as fs from 'node:fs/promises'
|
||||
|
||||
import * as env from '../src/env'
|
||||
|
||||
let file: FileResult
|
||||
beforeEach(() => (file = fileSync()))
|
||||
afterEach(() => file.removeCallback())
|
||||
|
||||
describe('File IO', () => {
|
||||
test('Can read file content', async () => {
|
||||
const message = 'coucou'
|
||||
await fs.writeFile(file.name, message)
|
||||
const res = await env.get_file_content(file.name)
|
||||
expect(res).toEqual({ok: true, data: message})
|
||||
})
|
||||
test("Fails safe if file doesn't exist", async () => {
|
||||
const res = await env.get_file_content('tralalero tralala')
|
||||
expect(res.ok).not.toBeTrue()
|
||||
})
|
||||
test('Reading a file trims whitespaces', async () => {
|
||||
const message = 'coucou\r\n\n\r\n'
|
||||
await fs.writeFile(file.name, message)
|
||||
const res = await env.from_file(file.name)
|
||||
expect(res).toEqual({ok: true, data: 'coucou'})
|
||||
})
|
||||
test.todo('Fails safe if no access to read')
|
||||
})
|
||||
describe('Folder', () => {
|
||||
let folder: DirResult
|
||||
beforeEach(() => (folder = dirSync()))
|
||||
afterEach(() => folder.removeCallback())
|
||||
test('Fails safe if path points to a folder', async () => {
|
||||
const res = await env.get_file_content(folder.name)
|
||||
expect(res.ok).not.toBeTrue()
|
||||
})
|
||||
})
|
||||
describe('read_env', () => {
|
||||
test('Can get value from env', async () => {
|
||||
const data = 'coucou'
|
||||
const key = 'DB_PORT'
|
||||
process.env[key] = data
|
||||
|
||||
const res = await env.read_env(key)
|
||||
expect(res).toEqual({ok: true, data})
|
||||
})
|
||||
test('Can get value from file', async () => {
|
||||
const data = 'coucou'
|
||||
const key = 'DB_PORT'
|
||||
process.env[`${key}__FILE`] = file.name
|
||||
await fs.writeFile(file.name, data)
|
||||
|
||||
const res = await env.read_env(key)
|
||||
expect(res).toEqual({ok: true, data})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,184 @@
|
||||
import {expect, test, describe, beforeEach} from 'bun:test'
|
||||
|
||||
import {yup} from '../src/index'
|
||||
import * as parsing from '../src/parsing'
|
||||
import {Ok} from '../src/helpers'
|
||||
|
||||
beforeEach(() => (process.env = {}))
|
||||
|
||||
describe('Object', () => {
|
||||
test('basic', async () => {
|
||||
const scheme = yup.object({})
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: {}})
|
||||
})
|
||||
|
||||
describe('empty', () => {
|
||||
test('Optional', async () => {
|
||||
const res = await parsing.object(yup.object({thing: yup.number()}))
|
||||
// @ts-expect-error empty is undefined, duh ??
|
||||
expect(res).toEqual({ok: true, data: {}})
|
||||
})
|
||||
test('Required missing', async () => {
|
||||
const res = await parsing.object(yup.object({thing: yup.number().required()}))
|
||||
expect(res.ok).not.toBeTrue()
|
||||
})
|
||||
test('default', async () => {
|
||||
const res = await parsing.object(yup.object({thing: yup.number().default(42)}))
|
||||
expect(res).toEqual({ok: true, data: {thing: 42}})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Nested objects', () => {
|
||||
test('One level', async () => {
|
||||
process.env = {
|
||||
NAME: 'test',
|
||||
PORT: '12',
|
||||
TS: '2025-06-08 23:51:12'
|
||||
}
|
||||
const scheme = yup.object({name: yup.string(), port: yup.number(), ts: yup.date()})
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: {name: 'test', port: 12, ts: new Date('2025-06-08 23:51:12')}})
|
||||
})
|
||||
test('Two levels', async () => {
|
||||
process.env = {
|
||||
DB_PORT: '12',
|
||||
DB_HOST: 'localhost',
|
||||
THING_A: 'Hello!',
|
||||
THING_B: '212',
|
||||
NAME: 'Pascal',
|
||||
AGE: '27'
|
||||
}
|
||||
const expected = {
|
||||
name: 'Pascal',
|
||||
age: 27,
|
||||
db: {
|
||||
port: 12,
|
||||
host: 'localhost'
|
||||
},
|
||||
thing: {
|
||||
a: 'Hello!',
|
||||
b: 212
|
||||
}
|
||||
}
|
||||
|
||||
const scheme = yup.object({
|
||||
name: yup.string().required(),
|
||||
age: yup.number().required(),
|
||||
db: yup
|
||||
.object({
|
||||
port: yup.number().required(),
|
||||
host: yup.string().required()
|
||||
})
|
||||
.required(),
|
||||
thing: yup
|
||||
.object({
|
||||
a: yup.string().required(),
|
||||
b: yup.number().required()
|
||||
})
|
||||
.required()
|
||||
})
|
||||
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: expected})
|
||||
})
|
||||
test('Three levels', async () => {
|
||||
process.env = {
|
||||
DB_HOST: 'localhost',
|
||||
THING_A: 'Hello!',
|
||||
AGE: '27',
|
||||
THING_THANG_A: '2025-06-06 23:56:12'
|
||||
}
|
||||
const expected = {
|
||||
age: 27,
|
||||
db: {
|
||||
host: 'localhost'
|
||||
},
|
||||
thing: {
|
||||
a: 'Hello!',
|
||||
thang: {
|
||||
a: new Date('2025-06-06 23:56:12')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const scheme = yup.object({
|
||||
age: yup.number(),
|
||||
db: yup.object({
|
||||
host: yup.string()
|
||||
}),
|
||||
thing: yup.object({
|
||||
a: yup.string(),
|
||||
thang: yup.object({
|
||||
a: yup.date()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const res = await parsing.object(scheme)
|
||||
expect(res).toEqual({ok: true, data: expected})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Specific parsing', () => {
|
||||
async function testing<T>(env_value: string, scheme: yup.AnySchema, should_be_successful: boolean, thing?: T) {
|
||||
process.env['THING'] = env_value
|
||||
const my_scheme = yup.object({thing: scheme})
|
||||
|
||||
const res: Ok<{thing: T}> = await parsing.object(my_scheme)
|
||||
// @ts-expect-error annoying typing issue, but it works, so, yk
|
||||
if (should_be_successful) expect(res).toEqual({ok: true, data: {thing}})
|
||||
else expect(res.ok).not.toBeTrue()
|
||||
}
|
||||
|
||||
describe('array', () => {
|
||||
test('basic', () => testing('1,2,3', yup.array(yup.number()), true, [1, 2, 3]))
|
||||
test('basic with whitespaces', () => testing(' 1 , 2 , 3 ', yup.array(yup.number()), true, [1, 2, 3]))
|
||||
test('Empty', () => testing('', yup.array(yup.number()), true, []))
|
||||
test('Empty fails with minimum length', () => testing('', yup.array(yup.number()).min(3), false))
|
||||
test('With minimum elements', () => testing('1,2,3', yup.array(yup.number()).min(3), true, [1, 2, 3]))
|
||||
})
|
||||
|
||||
describe('tuple', () => {
|
||||
test('basic', () => testing('1,2,3', yup.tuple([yup.number(), yup.number(), yup.number()]), true, [1, 2, 3]))
|
||||
test('Missing value', () => testing('1,2', yup.tuple([yup.number(), yup.number(), yup.number()]), false))
|
||||
test('Too much values', () => testing('1,2,3,4', yup.tuple([yup.number(), yup.number(), yup.number()]), false))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('generic', () => {
|
||||
async function testing(
|
||||
value: string | string[],
|
||||
scheme: yup.AnySchema,
|
||||
should_be_successful: boolean,
|
||||
data?: unknown
|
||||
) {
|
||||
const res = await parsing.generic(value, scheme)
|
||||
if (should_be_successful) expect(res).toEqual({ok: true, data})
|
||||
else expect(res.ok).not.toBeTrue()
|
||||
}
|
||||
|
||||
describe('Integer', () => {
|
||||
test('basic', () => testing('12', yup.number(), true, 12))
|
||||
test('string', () => testing('coucou', yup.number(), false))
|
||||
test('min-max OK', () => testing('12', yup.number().min(11).max(13), true, 12))
|
||||
test('min-max KO', () => testing('10', yup.number().min(11).max(13), false, 10))
|
||||
test('min-max KO 2', () => testing('10', yup.number().min(11).max(13), false, 14))
|
||||
})
|
||||
describe('String', () => {
|
||||
test('basic', () => testing('coucou', yup.string(), true, 'coucou'))
|
||||
test('Length min-max', () => testing('coucou', yup.string().max(7), true, 'coucou'))
|
||||
test('KO: Length min-max', () => testing('coucou', yup.string().max(5), false))
|
||||
})
|
||||
describe('boolean', () => {
|
||||
test('basic true', () => testing('true', yup.boolean(), true, true))
|
||||
test('basic false', () => testing('false', yup.boolean(), true, false))
|
||||
test('basic 1', () => testing('1', yup.boolean(), true, true))
|
||||
test('basic 0', () => testing('0', yup.boolean(), true, false))
|
||||
test('junk', () => testing('yeet', yup.boolean(), false))
|
||||
})
|
||||
describe('Date', () => {
|
||||
test('basic', () => testing('2025-06-08 22:40:17', yup.date(), true, new Date('2025-06-08 22:40:17')))
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user