2022-03-04 17:29:42 +01:00
import { constraintSchema , featureSchema , querySchema } from './feature-schema' ;
2018-12-12 10:09:38 +01:00
2021-05-28 11:10:24 +02:00
test ( 'should require URL firendly name' , ( ) = > {
2018-12-12 10:09:38 +01:00
const toggle = {
name : 'io`dasd' ,
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2018-12-12 10:09:38 +01:00
strategies : [ { name : 'default' } ] ,
} ;
2021-01-18 12:32:19 +01:00
const { error } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( error . details [ 0 ] . message ) . toEqual ( '"name" must be URL friendly' ) ;
2018-12-12 10:09:38 +01:00
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'should be valid toggle name' , ( ) = > {
2018-12-12 10:09:38 +01:00
const toggle = {
name : 'app.name' ,
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2018-12-12 10:09:38 +01:00
strategies : [ { name : 'default' } ] ,
} ;
2021-01-18 12:32:19 +01:00
const { value } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( value . name ) . toBe ( toggle . name ) ;
2018-12-12 10:09:38 +01:00
} ) ;
2019-01-29 09:21:54 +01:00
2021-05-28 11:10:24 +02:00
test ( 'should strip extra variant fields' , ( ) = > {
2019-01-29 09:21:54 +01:00
const toggle = {
name : 'app.name' ,
2020-08-06 11:18:52 +02:00
type : 'release' ,
2019-01-29 09:21:54 +01:00
enabled : false ,
2020-08-07 10:46:35 +02:00
stale : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2019-01-29 09:21:54 +01:00
strategies : [ { name : 'default' } ] ,
variants : [
{
name : 'variant-a' ,
weight : 1 ,
unkown : 'not-allowed' ,
} ,
] ,
} ;
2021-01-18 12:32:19 +01:00
const { value } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( value ) . not . toEqual ( toggle ) ;
expect ( value . variants [ 0 ] . unkown ) . toBeFalsy ( ) ;
2019-01-29 09:21:54 +01:00
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'should allow weightType=fix' , ( ) = > {
2020-08-03 13:24:51 +02:00
const toggle = {
name : 'app.name' ,
2020-08-06 11:18:52 +02:00
type : 'release' ,
2020-09-28 21:54:44 +02:00
project : 'default' ,
2020-08-03 13:24:51 +02:00
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2020-08-07 10:46:35 +02:00
stale : false ,
2021-07-07 10:46:50 +02:00
archived : false ,
2020-08-03 13:24:51 +02:00
strategies : [ { name : 'default' } ] ,
variants : [
{
name : 'variant-a' ,
weight : 1 ,
weightType : 'fix' ,
2021-02-11 17:59:16 +01:00
stickiness : 'default' ,
2020-08-03 13:24:51 +02:00
} ,
] ,
} ;
2021-01-18 12:32:19 +01:00
const { value } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( value ) . toEqual ( toggle ) ;
2020-08-03 13:24:51 +02:00
} ) ;
2023-01-05 12:39:18 +01:00
test ( 'should not allow weightType=fix with floats' , ( ) = > {
const toggle = {
name : 'app.name' ,
type : 'release' ,
project : 'default' ,
enabled : false ,
impressionData : false ,
stale : false ,
archived : false ,
strategies : [ { name : 'default' } ] ,
variants : [
{
name : 'variant-a' ,
weight : 1.5 ,
weightType : 'fix' ,
stickiness : 'default' ,
} ,
] ,
} ;
const { error } = featureSchema . validate ( toggle ) ;
expect ( error . details [ 0 ] . message ) . toEqual ( 'Weight only supports 1 decimal' ) ;
} ) ;
test ( 'should not allow weightType=fix with more than 1000' , ( ) = > {
const toggle = {
name : 'app.name' ,
type : 'release' ,
project : 'default' ,
enabled : false ,
impressionData : false ,
stale : false ,
archived : false ,
strategies : [ { name : 'default' } ] ,
variants : [
{
name : 'variant-a' ,
weight : 1001 ,
weightType : 'fix' ,
stickiness : 'default' ,
} ,
] ,
} ;
const { error } = featureSchema . validate ( toggle ) ;
expect ( error . details [ 0 ] . message ) . toEqual (
'"variants[0].weight" must be less than or equal to 1000' ,
) ;
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'should disallow weightType=unknown' , ( ) = > {
2020-08-03 13:24:51 +02:00
const toggle = {
name : 'app.name' ,
2020-08-06 11:18:52 +02:00
type : 'release' ,
2020-08-03 13:24:51 +02:00
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2020-08-07 10:46:35 +02:00
stale : false ,
2021-07-07 10:46:50 +02:00
archived : false ,
2020-08-03 13:24:51 +02:00
strategies : [ { name : 'default' } ] ,
variants : [
{
name : 'variant-a' ,
weight : 1 ,
weightType : 'unknown' ,
} ,
] ,
} ;
2021-01-18 12:32:19 +01:00
const { error } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( error . details [ 0 ] . message ) . toEqual (
2020-08-03 13:24:51 +02:00
'"variants[0].weightType" must be one of [variable, fix]' ,
) ;
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'should be possible to define variant overrides' , ( ) = > {
2019-01-29 09:21:54 +01:00
const toggle = {
name : 'app.name' ,
2020-08-06 11:18:52 +02:00
type : 'release' ,
2020-09-28 21:54:44 +02:00
project : 'some' ,
2019-01-29 09:21:54 +01:00
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2020-08-07 10:46:35 +02:00
stale : false ,
2021-07-07 10:46:50 +02:00
archived : false ,
2019-01-29 09:21:54 +01:00
strategies : [ { name : 'default' } ] ,
variants : [
{
name : 'variant-a' ,
weight : 1 ,
2020-08-03 13:24:51 +02:00
weightType : 'variable' ,
2021-02-11 17:59:16 +01:00
stickiness : 'default' ,
2019-01-29 09:21:54 +01:00
overrides : [
{
2019-02-04 14:04:58 +01:00
contextName : 'userId' ,
2019-01-29 09:21:54 +01:00
values : [ '123' ] ,
} ,
] ,
} ,
] ,
} ;
2021-01-18 12:32:19 +01:00
const { value , error } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( value ) . toEqual ( toggle ) ;
expect ( error ) . toBeFalsy ( ) ;
2019-01-29 09:21:54 +01:00
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'variant overrides must have corect shape' , async ( ) = > {
expect . assertions ( 1 ) ;
2019-01-29 09:21:54 +01:00
const toggle = {
name : 'app.name' ,
2020-08-06 11:18:52 +02:00
type : 'release' ,
2019-01-29 09:21:54 +01:00
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2020-08-07 10:46:35 +02:00
stale : false ,
2019-01-29 09:21:54 +01:00
strategies : [ { name : 'default' } ] ,
variants : [
{
name : 'variant-a' ,
weight : 1 ,
overrides : {
userId : [ 'not-alloed' ] ,
sessionId : [ 'not-alloed' ] ,
} ,
} ,
] ,
} ;
try {
2021-01-18 12:32:19 +01:00
await featureSchema . validateAsync ( toggle ) ;
2019-01-29 09:21:54 +01:00
} catch ( error ) {
2021-05-28 11:10:24 +02:00
expect ( error . details [ 0 ] . message ) . toBe (
2020-04-14 22:29:11 +02:00
'"variants[0].overrides" must be an array' ,
2020-01-02 19:23:52 +01:00
) ;
2019-01-29 09:21:54 +01:00
}
} ) ;
2019-11-20 22:11:30 +01:00
2021-05-28 11:10:24 +02:00
test ( 'should keep constraints' , ( ) = > {
2019-11-20 22:11:30 +01:00
const toggle = {
name : 'app.constraints' ,
2020-08-06 11:18:52 +02:00
type : 'release' ,
2020-09-28 21:54:44 +02:00
project : 'default' ,
2019-11-20 22:11:30 +01:00
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2020-08-07 10:46:35 +02:00
stale : false ,
2021-07-07 10:46:50 +02:00
archived : false ,
2019-11-20 22:11:30 +01:00
strategies : [
{
name : 'default' ,
constraints : [
{
contextName : 'environment' ,
operator : 'IN' ,
values : [ 'asd' ] ,
} ,
] ,
} ,
] ,
} ;
2021-01-18 12:32:19 +01:00
const { value , error } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( value ) . toEqual ( toggle ) ;
expect ( error ) . toBeFalsy ( ) ;
2019-11-20 22:11:30 +01:00
} ) ;
2020-10-30 10:30:28 +01:00
2021-05-28 11:10:24 +02:00
test ( 'should not accept empty constraint values' , ( ) = > {
2020-10-30 10:30:28 +01:00
const toggle = {
name : 'app.constraints.empty.value' ,
type : 'release' ,
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2020-10-30 10:30:28 +01:00
stale : false ,
strategies : [
{
name : 'default' ,
constraints : [
{
contextName : 'environment' ,
operator : 'IN' ,
values : [ '' ] ,
} ,
] ,
} ,
] ,
} ;
2021-01-18 12:32:19 +01:00
const { error } = featureSchema . validate ( toggle ) ;
2021-05-28 11:10:24 +02:00
expect ( error . details [ 0 ] . message ) . toEqual (
2020-10-30 10:30:28 +01:00
'"strategies[0].constraints[0].values[0]" is not allowed to be empty' ,
) ;
} ) ;
2022-03-17 12:32:04 +01:00
test ( 'should accept empty list of constraint values' , async ( ) = > {
2020-10-30 10:30:28 +01:00
const toggle = {
name : 'app.constraints.empty.value.list' ,
type : 'release' ,
enabled : false ,
2022-02-03 11:06:51 +01:00
impressionData : false ,
2020-10-30 10:30:28 +01:00
stale : false ,
strategies : [
{
name : 'default' ,
constraints : [
{
contextName : 'environment' ,
operator : 'IN' ,
values : [ ] ,
} ,
] ,
} ,
] ,
} ;
2022-03-17 12:32:04 +01:00
const validated = await featureSchema . validateAsync ( toggle ) ;
expect ( validated . strategies . length ) . toEqual ( 1 ) ;
expect ( validated . strategies [ 0 ] . constraints . length ) . toEqual ( 1 ) ;
expect ( validated . strategies [ 0 ] . constraints [ 0 ] . values ) . toEqual ( [ ] ) ;
2020-10-30 10:30:28 +01:00
} ) ;
2021-01-22 13:39:42 +01:00
2021-05-28 11:10:24 +02:00
test ( 'Filter queries should accept a list of tag values' , ( ) = > {
2021-01-22 13:39:42 +01:00
const query = {
tag : [ 'simple:valuea' , 'simple:valueb' ] ,
} ;
const { value } = querySchema . validate ( query ) ;
2021-05-28 11:10:24 +02:00
expect ( value ) . toEqual ( { tag : [ 'simple:valuea' , 'simple:valueb' ] } ) ;
2021-01-22 13:39:42 +01:00
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'Filter queries should reject tag values with missing type prefix' , ( ) = > {
2021-01-22 13:39:42 +01:00
const query = {
tag : [ 'simple' , 'simple' ] ,
} ;
const { error } = querySchema . validate ( query ) ;
2021-05-28 11:10:24 +02:00
expect ( error . details [ 0 ] . message ) . toEqual (
2021-01-22 13:39:42 +01:00
'"tag[0]" with value "simple" fails to match the tag pattern' ,
) ;
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'Filter queries should allow project names' , ( ) = > {
2021-01-22 13:39:42 +01:00
const query = {
project : [ 'projecta' ] ,
} ;
const { value } = querySchema . validate ( query ) ;
2021-05-28 11:10:24 +02:00
expect ( value ) . toEqual ( { project : [ 'projecta' ] } ) ;
2021-01-22 13:39:42 +01:00
} ) ;
2021-05-28 11:10:24 +02:00
test ( 'Filter queries should reject project names that are not alphanum' , ( ) = > {
2021-01-22 13:39:42 +01:00
const query = {
project : [ 'project name with space' ] ,
} ;
const { error } = querySchema . validate ( query ) ;
2021-05-28 11:10:24 +02:00
expect ( error . details [ 0 ] . message ) . toEqual (
'"project[0]" must be URL friendly' ,
) ;
2021-01-22 13:39:42 +01:00
} ) ;
2022-03-04 17:29:42 +01:00
test ( 'constraint schema should only allow specified operators' , async ( ) = > {
const invalidConstraint = {
contextName : 'semver' ,
operator : 'INVALID_OPERATOR' ,
value : 123123213123 ,
} ;
expect . assertions ( 1 ) ;
try {
await constraintSchema . validateAsync ( invalidConstraint ) ;
} catch ( error ) {
expect ( error . message ) . toBe (
'"operator" must be one of [NOT_IN, IN, STR_ENDS_WITH, STR_STARTS_WITH, STR_CONTAINS, NUM_EQ, NUM_GT, NUM_GTE, NUM_LT, NUM_LTE, DATE_AFTER, DATE_BEFORE, SEMVER_EQ, SEMVER_GT, SEMVER_LT]' ,
) ;
}
} ) ;
2022-03-17 12:32:04 +01:00
test ( 'constraint schema should add a values array by default' , async ( ) = > {
const validated = await constraintSchema . validateAsync ( {
contextName : 'x' ,
operator : 'NUM_EQ' ,
value : 1 ,
} ) ;
expect ( validated ) . toEqual ( {
contextName : 'x' ,
operator : 'NUM_EQ' ,
value : 1 ,
values : [ ] ,
} ) ;
} ) ;