Skip to content

Commit

Permalink
fix: fixed withTooltip behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
victorgarciaesgi committed Dec 10, 2024
1 parent 8f8c41b commit eb7120e
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 47 deletions.
3 changes: 2 additions & 1 deletion packages/core/src/core/createRule/createRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ export function createRule<
ruleFactory._active = staticProcessors.active;
ruleFactory._tooltip = staticProcessors.tooltip;
ruleFactory._type = definition.type;
ruleFactory._patched = false;
ruleFactory._message_pacthed = false;
ruleFactory._tooltip_pacthed = false;
ruleFactory._async = isAsync as TAsync;
return ruleFactory as any;
} else {
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/core/createRule/defineRuleProcessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ export function defineRuleProcessors(
_active: definition.active,
_tooltip: definition.tooltip,
_type: definition.type,
_patched: false,
_message_patched: false,
_tooltip_patched: false,
_async: isAsync,
_params: createReactiveParams<never>(params),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import type { ComputedRef, Ref, WatchStopHandle } from 'vue';
import { computed, effectScope, reactive, ref, watch } from 'vue';
import { isEmpty } from '../../../../../shared';
import type {
$InternalInlineRuleDeclaration,
$InternalRegleRuleDefinition,
$InternalRegleRuleMetadataConsumer,
$InternalRegleRuleStatus,
CustomRulesDeclarationTree,
InlineRuleDeclaration,
RegleRuleDefinition,
RegleRuleDefinitionProcessor,
RegleRuleMetadataDefinition,
} from '../../../types';
import { debounce } from '../../../utils';
import { unwrapRuleParameters } from '../../createRule/unwrapRuleParameters';
import type { RegleStorage } from '../../useStorage';
import { isFormRuleDefinition, isRuleDef } from '../guards';
import { isEmpty } from '../../../../../shared';

interface CreateReactiveRuleStatusOptions {
state: Ref<unknown>;
ruleKey: string;
rule: Ref<InlineRuleDeclaration<any, any[], any> | RegleRuleDefinition<any, any, any>>;
rule: Ref<$InternalInlineRuleDeclaration | $InternalRegleRuleDefinition>;
$dirty: Ref<boolean>;
customMessages: CustomRulesDeclarationTree | undefined;
path: string;
Expand Down Expand Up @@ -88,7 +89,8 @@ export function createReactiveRuleStatus({
}
}
if (isFormRuleDefinition(rule)) {
if (!(customMessageRule && !rule.value._patched)) {
const patchedKey = `_${key}_patched` as const;
if (!(customMessageRule && !rule.value[patchedKey])) {
if (typeof rule.value[key] === 'function') {
result = rule.value[key](state.value, $defaultMetadata.value);
} else {
Expand All @@ -104,7 +106,9 @@ export function createReactiveRuleStatus({

if (isEmpty(message)) {
message = 'Error';
console.warn(`No error message defined for ${path}.${ruleKey}`);
if (typeof window !== 'undefined') {
console.warn(`No error message defined for ${path}.${ruleKey}`);
}
}

return message;
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/types/rules/rule.declaration.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ export type InlineRuleDeclaration<
| Promise<RegleRuleMetadataDefinition>,
> = (value: Maybe<TValue>, ...args: UnwrapRegleUniversalParams<TParams>) => TReturn;

/**
* @internal
*/
export type $InternalInlineRuleDeclaration = (value: Maybe<any>, ...args: any[]) => any;

/**
* @public
* Regroup inline and registered rules
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/types/rules/rule.internal.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export interface RegleInternalRuleDefs<
| string[]
| ((value: Maybe<TValue>, metadata: PossibleRegleRuleMetadataConsumer) => string | string[]);
_type?: string;
_patched: boolean;
_message_patched: boolean;
_tooltip_patched: boolean;
_params?: RegleUniversalParams<TParams>;
_async: TAsync;
}
Expand Down
10 changes: 3 additions & 7 deletions packages/rules/src/helpers/withMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ export function withMessage<
): RegleRuleDefinition<TValue, TParams, TAsync, TMetadata>;
export function withMessage(
rule: RegleRuleRaw<any, any, any, any> | InlineRuleDeclaration<any, any>,
newMessage: RegleRuleDefinitionWithMetadataProcessor<
any,
RegleRuleMetadataConsumer<any[], any>,
string | string[]
>
newMessage: RegleRuleDefinitionWithMetadataProcessor<any, RegleRuleMetadataConsumer<any[], any>, string | string[]>
): RegleRuleWithParamsDefinition<any, any, any, any> | RegleRuleDefinition<any, any, any, any> {
let _type: string | undefined;
let validator: RegleRuleDefinitionProcessor<any | Promise<any>>;
Expand All @@ -85,11 +81,11 @@ export function withMessage(
const newParams = [...(_params ?? [])];

newRule._params = newParams as any;
newRule._patched = true;
newRule._message_patched = true;

if (typeof newRule === 'function') {
const executedRule = newRule(...newParams);
executedRule._patched = true;
executedRule._message_patched = true;
return executedRule;
} else {
return newRule;
Expand Down
2 changes: 2 additions & 0 deletions packages/rules/src/helpers/withTooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,11 @@ export function withTooltip(
const newParams = [...(_params ?? [])];

newRule._params = newParams as any;
newRule._tooltip_patched = true;

if (typeof newRule === 'function') {
const executedRule = newRule(...newParams);
newRule._tooltip_patched = true;
return executedRule;
} else {
return newRule;
Expand Down
147 changes: 117 additions & 30 deletions tests/unit/useRegle/errors/metadata.spec.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,143 @@
import { createRule, useRegle } from '@regle/core';
import { withMessage, withParams } from '@regle/rules';
import { createRule, useRegle, type Maybe } from '@regle/core';
import { withMessage, withParams, withTooltip } from '@regle/rules';
import { ref } from 'vue';
import { createRegleComponent } from '../../../utils/test.utils';

function metadateRules() {
const externalDep = ref('external');
const inlineMetadataRule = withMessage(
withParams((value, external) => ({ $valid: false, external, value }), [externalDep]),
(_, { external, value }) => `${external}-${value}`
const inlineMetadataRule = withTooltip(
withMessage(
withParams(
(value: Maybe<string | any[]>, external) => ({ $valid: false, metaExternal: external, value }),
[externalDep]
),
(_, { metaExternal, value, $params: [external] }) => `${metaExternal}-${external}-${value?.length}`
),
(_, { metaExternal, value, $params: [external] }) => `${metaExternal}-${external}-${value?.length}`
);
const createRuleMetadataRule = createRule({
validator: (value, external) => ({ $valid: false, external, value }),
message: (_, { external, value }) => `${external}-${value}`,
validator: (value: Maybe<string | any[]>, external) => ({ $valid: false, metaExternal: external, value }),
message: (_, { metaExternal, value, $params: [external] }) => `${metaExternal}-${external}-${value?.length}`,
tooltip: (_, { metaExternal, value, $params: [external] }) => `${metaExternal}-${external}-${value?.length}`,
active: (_, { $params: [external] }) => external === 'external',
});

const form = ref({
email: '',
email: 'a',
user: {
firstName: '',
firstName: 'a',
nested: {
child: '',
collection: [{ name: '' }],
child: 'a',
collection: [{ name: 'a' }],
},
},
contacts: [{ name: '' }],
contacts: [{ name: 'a' }],
});

const allRules = { inlineMetadataRule, createRuleMetadataRule: createRuleMetadataRule(externalDep) };

return useRegle(form, {
email: allRules,
user: {
firstName: allRules,
nested: {
child: allRules,
collection: {
...allRules,
$each: {
name: allRules,
return {
externalDep,
...useRegle(form, {
email: allRules,
user: {
firstName: allRules,
nested: {
child: allRules,
collection: {
...allRules,
$each: {
name: allRules,
},
},
},
},
},
contacts: {
$each: {
name: allRules,
contacts: {
$each: {
name: allRules,
},
},
},
});
}),
};
}

describe('metadata', () => {
it('correctly return metadata for validator and active handlers', () => {
expect(true).toBe(true);
it('correctly return metadata for validator and active handlers', async () => {
const { vm } = createRegleComponent(metadateRules);

vm.r$.$touch();
await vm.$nextTick();

const expectedMessage = ['external-external-1', 'external-external-1'];

expect(vm.r$.$fields.email.$errors).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.firstName.$errors).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.nested.$fields.child.$errors).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$field.$errors).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$each[0].$fields.name.$errors).toStrictEqual(
expectedMessage
);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$errors).toStrictEqual(expectedMessage);

// Tooltips
expect(vm.r$.$fields.email.$tooltips).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.firstName.$tooltips).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.nested.$fields.child.$tooltips).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$field.$tooltips).toStrictEqual(expectedMessage);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$each[0].$fields.name.$tooltips).toStrictEqual(
expectedMessage
);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$tooltips).toStrictEqual(expectedMessage);

// Active
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.createRuleMetadataRule.$active).toBe(true);
expect(vm.r$.$fields.email.$rules.createRuleMetadataRule.$active).toBe(true);
expect(vm.r$.$fields.user.$fields.firstName.$rules.createRuleMetadataRule.$active).toBe(true);
expect(vm.r$.$fields.user.$fields.nested.$fields.child.$rules.createRuleMetadataRule.$active).toBe(true);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$field.$rules.createRuleMetadataRule.$active).toBe(
true
);
expect(
vm.r$.$fields.user.$fields.nested.$fields.collection.$each[0].$fields.name.$rules.createRuleMetadataRule.$active
).toBe(true);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.createRuleMetadataRule.$active).toBe(true);

// Change value
vm.externalDep = 'new';
await vm.$nextTick();

const expectedMessage2 = ['new-new-1', 'new-new-1'];

expect(vm.r$.$fields.email.$errors).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.firstName.$errors).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.nested.$fields.child.$errors).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$field.$errors).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$each[0].$fields.name.$errors).toStrictEqual(
expectedMessage2
);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$errors).toStrictEqual(expectedMessage2);

// Tooltips
expect(vm.r$.$fields.email.$tooltips).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.firstName.$tooltips).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.nested.$fields.child.$tooltips).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$field.$tooltips).toStrictEqual(expectedMessage2);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$each[0].$fields.name.$tooltips).toStrictEqual(
expectedMessage2
);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$tooltips).toStrictEqual(expectedMessage2);

// Active
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.createRuleMetadataRule.$active).toBe(false);
expect(vm.r$.$fields.email.$rules.createRuleMetadataRule.$active).toBe(false);
expect(vm.r$.$fields.user.$fields.firstName.$rules.createRuleMetadataRule.$active).toBe(false);
expect(vm.r$.$fields.user.$fields.nested.$fields.child.$rules.createRuleMetadataRule.$active).toBe(false);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$field.$rules.createRuleMetadataRule.$active).toBe(
false
);
expect(
vm.r$.$fields.user.$fields.nested.$fields.collection.$each[0].$fields.name.$rules.createRuleMetadataRule.$active
).toBe(false);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.createRuleMetadataRule.$active).toBe(false);
});
});
Loading

0 comments on commit eb7120e

Please sign in to comment.